我有以下代码为最初作为共享变量count = 0的N个线程运行。每个变量在线程工作之前初始化。我试图只为MAX个线程执行代码的关键部分。
void *tmain(){
while(1){
pthread_mutex_lock(&count_mutex);
count++;
if(count>MAX){
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
pthread_mutex_unlock(&count_mutex);
/*
some code not associated with count_mutex or count_threshold_cv
*/
pthread_mutex_lock(&count_mutex);
count--;
pthread_cond_signal(&count_threshold_cv);
pthread_mutex_unlock(&count_mutex);
}
}
但是在运行一段时间之后,线程在pthread_cond_signal()处被阻塞。我无法理解为什么会这样。任何帮助表示赞赏。
答案 0 :(得分:3)
此代码有一个可能导致阻塞问题的弱点。
更准确地说,它不受所谓的虚假醒来的保护,
这意味着当没有信号通过调用pthread_cond_signal()或pthread_cond_broadcast()传递显式时,pthread_cond_wait()函数可能会返回。
因此,当计数变量小于或等于 MAX
if(count>MAX){
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
让我们看看当计数仍大于MAX时,当一个线程被唤醒时会发生什么: 之后立即解锁互斥锁。 现在,其他线程可以进入关键会话并增加计数变量超过预期:
pthread_mutex_lock(&count_mutex);
count++;
如何保护代码免受虚假信号的侵害? pthread_cond_wait唤醒是检查谓词(count> MAX)的建议。 如果它仍然是假的,我们需要继续等待条件变量。 尝试通过将 if 语句更改为 while 语句来修复代码(并且,正如@alk所说,更改tmain()签名):
while(count>MAX)
{
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
现在,如果发生虚假唤醒并且计数仍然大于MAX, 流将再次等待条件变量。只有当唤醒伴随着谓词变化时,流才会逃脱等待循环。
答案 1 :(得分:0)
您的代码阻止的原因是因为您在等待之前放置了count ++:
count++;
if(count>MAX){
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
相反,你应该写
while (count >= MAX) {
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
count++;
原因是count应该是工作线程的数量。 一个线程只能在等待时递增计数。
另一方面,计数变量计算工作线程数加上等待线程数。该计数太大并导致条件计数> MAX为真阻止。
你也应该替换"如果"与"而"正如MichaelGoren所写。使用"如果"而不是"而#34;不会导致阻塞,而是导致太多线程同时运行;即使计数>唤醒的线程也开始工作MAX。
你需要"而#34;是pthread_cond_signal解除阻塞其中一个等待线程。但是,未阻塞的线程仍在等待互斥锁,并且它不一定要安排运行。当唤醒线程最终获取互斥锁并开始运行时,对pthread_cond_wait的调用返回。同时,在pthread_cond_signal和pthread_cond_wait的返回之间,其他线程可能拥有互斥锁。所以你必须再次检查条件,这是什么"而"确实
另外,因为count ++现在等待,所以条件变为count> = MAX而不是count> MAX。即使工人数量为MAX,您也应该等待。
或者,您可以使用信号量来解决此问题。