我正在关注来自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
计算?在functionCount1
的while循环中,它在包括3的任何值上调用wait()
,这使我认为3应该由functionCount2
而不是functionCount1
计算。
为什么不是这样?
一个线程可以读取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
仍有可能执行从3到4的增量。这是因为在functionCount1
之间看到count
值为2并决定不等待,并且实际锁定count_mutex
,该值可以由另一个线程递增。
要删除对count
的非同步访问并修复上一段中引用的种族,你只需完全删除condition_mutex
并使用count_mutex
代替,保持它在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
时不需要锁定printf()
,只要您将新的count
值的本地副本传递给printf()
即可。您也可以在退出测试中使用该本地副本。
此外,只需要在functionCount2()
改变count
后测试信号条件。 pthread_mutex_signal()
不必在持有互斥锁的情况下调用,所以我们也可以在printf()
之后使用计数的本地副本:
void *functionCount1()
{
for(;;)
{
int my_count;
pthread_mutex_lock( &count_mutex );
while( count >= COUNT_HALT1 && count <= COUNT_HALT2 )
{
pthread_cond_wait( &condition_cond, &count_mutex );
}
count++;
my_count = count;
pthread_mutex_unlock( &count_mutex );
printf("Counter value functionCount1: %d\n", my_count);
if (my_count >= COUNT_DONE)
return(NULL);
}
}
void *functionCount2()
{
for(;;)
{
int my_count;
pthread_mutex_lock( &count_mutex );
count++;
my_count = count;
pthread_mutex_unlock( &count_mutex );
printf("Counter value functionCount2: %d\n", my_count);
if ( my_count < COUNT_HALT1 || my_count > COUNT_HALT2 )
{
pthread_cond_signal( &condition_cond );
}
if (my_count >= COUNT_DONE)
return(NULL);
}
}
如上所述,您可能不会再看到以严格计数顺序排序的printf()
输出,因为我们不再强制printf()以增量的形式原子地发生。