在我的程序中,有一部分代码等待从代码的其他部分唤醒:
这是睡觉的部分:
void flush2device(int task_id) {
if (pthread_mutex_lock(&id2cvLock) != SUCCESS) {
cerr << "system error - exiting!!!\n";
exit(1);
}
map<int,pthread_cond_t*>::iterator it;
it = id2cv.find(task_id);
if(it == id2cv.end()){
if (pthread_mutex_unlock(&id2cvLock) != SUCCESS) {
cerr << "system error\n UNLOCKING MUTEX flush2device\n";
exit(1);
}
return;
}
cout << "Waiting for CV signal" <<endl;
if(pthread_cond_wait(it->second, &id2cvLock)!=SUCCESS){
cerr << "system error\n COND_WAIT flush2device - exiting!!!\n";
exit(1);
}
cout << "should be right after " << task_id << " signal" << endl;
if (pthread_mutex_unlock(&id2cvLock) != SUCCESS) {
cerr << "system error\n UNLOCKING MUTEX flush2device -exiting!!!\n";
exit(1);
}
}
在代码的另一部分,有醒来部分(信令):
//id2cv is a map <int, pthread_cond_t*> variable. - the value is a pointer to the cv on
//which we call with the broadcast method.
if(pthread_mutex_lock(&id2cvLock)!=SUCCESS){
cerr <<"system error\n";
exit(1);
}
id2cv.erase(nextBuf->_taskID);
cout << "In Thread b4 signal, i'm tID " <<nextBuf->_taskID << endl;
if (pthread_cond_broadcast(nextBuf->cv) != 0) {
cerr << "system error SIGNAL_CV doThreads\n";
exit(1);
}
cout << "In doThread, after erasing id2cv " << endl;
if(pthread_mutex_unlock(&id2cvLock)!=SUCCESS){
cerr <<"system error\n;
exit(1);
}
大多数运行都运行得很好,但偶尔程序只是停止“反应” - 第一种方法(上面)只是没有通过cond_wait部分 - 似乎没有人真正发送她的信号时间(或其他原因) - 而另一种方法(代码的最后一部分是其中的一部分)继续运行。
我在互斥和信号的逻辑上哪里出错了?我已经检查过pthread_cond_t变量在调用cond_wait和cond_broadcast方法之前仍处于“活动状态”,并且该区域中没有任何内容似乎是错误的。
答案 0 :(得分:5)
尽管名称如此,pthread_cond_wait
是联合条件等待 条件。除非您已确认有待等待的内容,否则不得致电pthread_cond_wait
,并且其等待的内容必须受相关联的互斥锁保护。
条件变量是无状态的,应用程序负责存储等待事物的状态,称为“谓词”。
规范模式是:
pthread_mutex_lock(&mutex);
while(!ready_for_me_to_do_something)
pthread_cond_wait(&condvar, &mutex);
do_stuff();
ready_for_me_to_do_something=false; // this may or may not be appropriate
pthread_mutex_unlock(&mutex);
和
pthread_mutex_lock(&mutex);
ready_for_me_to_do_something=true;
pthread_cond_broadcast(&condvar);
pthread_mutex_unlock(&mutex);
注意这段代码如何维护ready_for_me_to_do_something
变量中的状态,等待线程在循环中等待,直到该变量为真。注意互斥锁如何保护共享变量,它保护条件变量(因为它也在线程之间共享)。
这不是使用条件变量的唯一正确方法,但很容易在任何其他用途中遇到麻烦。即使没有理由等待,也可以致电pthread_cond_wait
。如果你在使用之前等待你的妹妹回家,并且她已经回来了,你将会等待很长时间。
答案 1 :(得分:2)
您对pthread_cond_wait()
的使用不正确。如果在没有进程等待的情况下发出条件变量信号,则该信号无效。它不会在下次进程等待时保存。这意味着正确使用pthread_cond_wait()
看起来像:
pthread_mutex_lock(&mutex);
/* ... */
while (!should_wake_up)
pthread_cond_wait(&cond, &mutex);
should_wake_up
条件可能只是对标志变量的简单测试,或者它可能类似于缓冲区为空或满或更类似的更复杂的测试。必须锁定互斥锁以防止可能会更改should_wake_up
的结果的并发修改。
目前还不清楚程序中的测试应该是什么 - 您可能需要添加一个特定的标志变量。
答案 2 :(得分:0)
我认为“唤醒”部分中没有足够的代码,但我最初的猜测是pthread_cond_wait
在pthread_cond_broadcast
发出时尚未输入。
另一种可能性是pthread_cond_wait
正处于虚假唤醒的中间并且完全错过了信号。
我很确定大多数条件变量的使用也有一个外部谓词,每次唤醒后都必须检查它,看看是否有工作要做。