20

我正在尝试学习 pthread_cond_wait 的基础知识。在所有用法中,我看到

if(cond is false)
   pthread_cond_wait

或者

while(cond is false)
   pthread_cond_wait

我的问题是,我们只想 cond_wait 因为条件为假。那我为什么要痛苦地明确放置一个 if/while 循环。我可以理解,在cond_wait我们直接点击它之前没有任何 if/while 检查,它根本不会返回。条件检查只是为了解决这个目的还是有其他意义。如果它用于解决不必要的条件等待,那么进行条件检查并避免 cond_wait 类似于轮询??我正在像这样使用 cond_wait 。

void* proc_add(void *name){
    struct vars *my_data = (struct vars*)name;
    printf("In thread Addition and my id = %d\n",pthread_self());
    while(1){
    pthread_mutex_lock(&mutexattr);
    while(!my_data->ipt){  // If no input get in
            pthread_cond_wait(&mutexaddr_add,&mutexattr);  // Wait till signalled
            my_data->opt = my_data->a + my_data->b;
            my_data->ipt=1;
            pthread_cond_signal(&mutexaddr_opt);
    }
    pthread_mutex_unlock(&mutexattr);
    if(my_data->end)
            pthread_exit((void *)0);
    }
}

逻辑是,只要输入可用,我就要求输入线程处理数据,并向输出线程发出信号以打印它。

4

2 回答 2

29

您需要一个 while 循环,因为即使未达到您等待的条件,调用的线程也pthread_cond_wait可能会唤醒。这种现象称为“虚假唤醒”。

这不是错误,它是条件变量的实现方式。

这也可以在手册页中找到:

可能会发生来自 pthread_cond_timedwait() 或 pthread_cond_wait() 函数的虚假唤醒。由于 pthread_cond_timedwait() 或 pthread_cond_wait() 的返回并不意味着该谓词的任何值,因此应在返回时重新评估谓词

关于实际代码的更新:

void* proc_add(void *name) 
{
    struct vars *my_data = (struct vars*)name;

    printf("In thread Addition and my id = %d\n",pthread_self());

    while(1) {

        pthread_mutex_lock(&mutexattr);

        while(!my_data->ipt){  // If no input get in
            pthread_cond_wait(&mutexaddr_add,&mutexattr);  // Wait till signalled
        }

        my_data->opt = my_data->a + my_data->b;
        my_data->ipt=1;
        pthread_cond_signal(&mutexaddr_opt);

        pthread_mutex_unlock(&mutexattr);

        if(my_data->end)
            pthread_exit((void *)0);
        }
    }
}
于 2012-10-29T13:18:57.047 回答
14

您必须在等待之前测试互斥锁下的条件,因为条件变量的信号没有排队(条件变量不是信号量)。也就是说,如果一个线程pthread_cond_signal()在没有线程被阻塞在pthread_cond_wait()该条件变量上时调用,那么信号什么也不做。

这意味着如果您有一个线程设置条件:

pthread_mutex_lock(&m);
cond = true;
pthread_cond_signal(&c);
pthread_mutex_unlock(&m);

然后另一个线程无条件等待:

pthread_mutex_lock(&m);
pthread_cond_wait(&c, &m);
/* cond now true */

这第二个线程将永远阻塞。这可以通过让第二个线程检查条件来避免:

pthread_mutex_lock(&m);
if (!cond)
    pthread_cond_wait(&c, &m);
/* cond now true */

由于cond仅使用m持有的互斥锁进行修改,这意味着当且仅当cond为假时,第二个线程才等待。

while ()在健壮的代码中使用循环而不是循环的原因if ()是因为pthread_cond_wait()不能保证它不会被虚假唤醒。使用 awhile ()还意味着向条件变量发出信号始终是完全安全的——“额外”信号不会影响程序的正确性,这意味着您可以执行诸如将信号移到代码锁定部分之外的操作。

于 2012-10-29T14:04:39.080 回答