pthread_cond_wait没有从pthread_cond_broadcast中醒来

时间:2011-04-07 13:42:50

标签: c++ pthreads

在我的程序中,有一部分代码等待从代码的其他部分唤醒:
这是睡觉的部分:

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方法之前仍处于“活动状态”,并且该区域中没有任何内容似乎是错误的。

3 个答案:

答案 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_waitpthread_cond_broadcast发出时尚未输入。

另一种可能性是pthread_cond_wait正处于虚假唤醒的中间并且完全错过了信号。

我很确定大多数条件变量的使用也有一个外部谓词,每次唤醒后都必须检查它,看看是否有工作要做。