pthread和条件变量

时间:2019-02-23 08:41:49

标签: concurrency pthreads condition-variable

我正在关注here中有关pthread的教程。

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

pthread_mutex_t count_mutex     = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  condition_cond  = PTHREAD_COND_INITIALIZER;

void *functionCount1();
void *functionCount2();
int  count = 0;
#define COUNT_DONE  10
#define COUNT_HALT1  3
#define COUNT_HALT2  6

main()
{
   pthread_t thread1, thread2;

   pthread_create( &thread1, NULL, &functionCount1, NULL);
   pthread_create( &thread2, NULL, &functionCount2, NULL);
   pthread_join( thread1, NULL);
   pthread_join( thread2, NULL);

   exit(0);
}

void *functionCount1()
{
   for(;;)
   {
      pthread_mutex_lock( &condition_mutex );
      while( count >= COUNT_HALT1 && count <= COUNT_HALT2 )
      {
         pthread_cond_wait( &condition_cond, &condition_mutex );
      }
      pthread_mutex_unlock( &condition_mutex );

      pthread_mutex_lock( &count_mutex );
      count++;
      printf("Counter value functionCount1: %d\n",count);
      pthread_mutex_unlock( &count_mutex );

      if(count >= COUNT_DONE) return(NULL);
    }
}

void *functionCount2()
{
    for(;;)
    {
       pthread_mutex_lock( &condition_mutex );
       if( count < COUNT_HALT1 || count > COUNT_HALT2 )
       {
          pthread_cond_signal( &condition_cond );
       }
       pthread_mutex_unlock( &condition_mutex );

       pthread_mutex_lock( &count_mutex );
       count++;
       printf("Counter value functionCount2: %d\n",count);
       pthread_mutex_unlock( &count_mutex );

       if(count >= COUNT_DONE) return(NULL);
    }

}

作者还补充说,functioncount1()在值COUNT_HALT1COUNT_HALT2之间暂停。

示例输出如下:

Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3
Counter value functionCount2: 4
Counter value functionCount2: 5
Counter value functionCount2: 6
Counter value functionCount2: 7
Counter value functionCount1: 8
Counter value functionCount1: 9
Counter value functionCount1: 10
Counter value functionCount2: 11

从我对代码的观察来看,functionCount2不应算为3吗?在functionCount1的while循环中,它会在任意值包括 3上调用wait(),这使我认为functionCount2应该将3计入,而不是functionCount1

为什么不是这样?

1 个答案:

答案 0 :(得分:1)

一个线程可能仅持有count(其中condition_mutex是针对countCOUNT_HALT1进行测试的)COUNT_HALT或根本没有互斥量的读取(其中count已针对COUNT_DONE进行了测试),而另一个线程可以在仅持有count的情况下修改count_mutex。正如@EOF在问题注释中指出的那样,这种不同步的访问导致不确定的行为,因此代码根本是不正确的。

也就是说,即使我们只运行functionCount1()而没有其他线程(这样就不会发生非同步访问),我们仍然希望看到以下输出:

Counter value functionCount1: 1
Counter value functionCount1: 2
Counter value functionCount1: 3

那是因为计数器值是在增量后 打印的,所以在上一次迭代中,它看到初始计数器值为2,无需等待,就递增计数器,然后打印新的计数器值3。

请注意,在您的原始代码中,即使忽略非同步访问,functionCount1仍然有可能functionCount1执行从3到4的增量。这是因为在{{ 1}}看到count的值为2并决定不等待,并实际上锁定了count_mutex,该值可以由另一个线程递增。

要同时删除对count的非同步访问并解决上一段中提到的问题,只需完全删除condition_mutex并使用count_mutex即可,将其锁定在{ {1}}返回和pthread_cond_wait()的实际增量。这是一般模式:调用count时锁定的互斥锁应该是通过条件变量保护正在等待的共享状态的互斥锁(此处,共享状态仅为pthread_cond_wait()变量):

count

这不是最佳选择:互斥锁保持锁定的时间比必要的时间长。如果您不关心线程之间的任意输出交织,则在调用void *functionCount1() { for(;;) { pthread_mutex_lock( &count_mutex ); while( count >= COUNT_HALT1 && count <= COUNT_HALT2 ) { pthread_cond_wait( &condition_cond, &count_mutex ); } count++; printf("Counter value functionCount1: %d\n",count); if (count >= COUNT_DONE) { pthread_mutex_unlock( &count_mutex ); return(NULL); } pthread_mutex_unlock( &count_mutex ); } } void *functionCount2() { for(;;) { pthread_mutex_lock( &count_mutex ); if( count < COUNT_HALT1 || count > COUNT_HALT2 ) { pthread_cond_signal( &condition_cond ); } count++; printf("Counter value functionCount2: %d\n",count); if (count >= COUNT_DONE) { pthread_mutex_unlock( &count_mutex ); return(NULL); } pthread_mutex_unlock( &count_mutex ); } } 时无需锁定count_mutex,只要获取新{{ 1}}的值传递给printf()。您还可以在退出测试中使用该本地副本。

此外,仅在count更改printf() 测试信令条件。 functionCount2()不必在保持互斥锁的情况下调用,因此我们也可以使用count的本地副本将其放在count之后:

pthread_mutex_signal()

如上所述,您可能再也看不到严格按计数顺序排列的printf()输出了,因为我们不再强迫printf()随增量自动发生。