pthread_cond_信号阻塞线程
以下代码最初作为共享变量为N个count=0的线程运行。每个变量都在线程工作之前初始化。我试图只为最大线程数执行代码的关键部分pthread_cond_信号阻塞线程,c,multithreading,pthreads,C,Multithreading,Pthreads,以下代码最初作为共享变量为N个count=0的线程运行。每个变量都在线程工作之前初始化。我试图只为最大线程数执行代码的关键部分 void *tmain(){ while(1){ pthread_mutex_lock(&count_mutex); count++; if(count>MAX){ pthread_cond_wait(&count_threshold_cv, &count_mutex); } p
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()处被阻塞。我无法理解为什么会发生这种情况。非常感谢您的帮助。此代码有一个可能导致阻塞问题的弱点。 更准确地说,它不受所谓的“虚假唤醒”的保护, 这意味着,通过调用pthread_cond_signal()或pthread_cond_broadcast(),pthread_cond_wait()函数可以在没有显式传递信号时返回。
因此,代码中的以下行不能保证线程在count变量小于或等于MAX时唤醒
if(count>MAX){
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
让我们看看当一个线程在计数仍然大于MAX时被唤醒时会发生什么:
紧接着,互斥锁被解锁。
现在,其他线程可以进入关键会话,并将count变量的增量超过预期值:
pthread_mutex_lock(&count_mutex);
count++;
如何保护代码不受虚假信号的影响?
建议使用pthread_cond_wait唤醒来检查谓词(count>MAX)。
如果仍然为false,则需要继续等待条件变量。
尝试通过将if语句更改为while语句来修复代码(并且,如@alk所述,更改tmain()签名):
现在,如果出现虚假唤醒,并且计数仍然大于MAX,
流将再次等待条件变量。只有当唤醒伴随谓词更改时,流才会退出等待循环 代码阻塞的原因是您将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应该是工作线程的数量。
线程只能在等待完成时增加计数
另一方面,count变量计算工作线程数加上等待线程数。此计数太大,导致条件计数>最大值为true,从而导致阻塞
正如MichaelGoren所写,您还应该将“if”替换为“while”。使用“if”而不是“while”不会导致阻塞,而是会导致太多线程同时运行;即使count>MAX,唤醒的线程也会开始工作
需要“while”的原因是pthread_cond_信号解除了其中一个等待线程的阻塞。但是,未阻塞的线程仍在等待互斥锁,并且不一定计划运行互斥锁。当被唤醒的线程最终获取互斥体并开始运行时,对pthread_cond_wait的调用将返回。同时,在pthread_cond_信号和pthread_cond_wait返回之间,其他线程可能拥有互斥锁。因此,您必须再次检查条件,“while”就是这样做的
此外,由于count++现在在等待之后,因此条件变为count>=MAX,而不是count>MAX。即使工人数量为MAX,也应该等待
或者,您也可以使用信号量来解决此问题。调用
pthread\u cond\u signal
不能在正常程序中死锁。您应该验证正在操作的条件变量是否仍然有效,并且没有损坏。另外,使用调试器来验证在死锁发生时不同线程被阻塞的确切位置,以及它们在该点上持有的锁。如果它不起作用,问题就在别处。顺便说一句:如果tmain()
作为线程函数传递给pthread\u create()
,则应声明:void*tmain(void*)
。我添加了[C]标记。如果您正在使用[C++],请更正此问题。
while (count >= MAX) {
pthread_cond_wait(&count_threshold_cv, &count_mutex);
}
count++;