我正在关注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_HALT1
和COUNT_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
。
为什么不是这样?
答案 0 :(得分:1)
一个线程可能仅持有count
(其中condition_mutex
是针对count
和COUNT_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()随增量自动发生。