为什么我们需要在pthread_cond_wait之前进行条件检查

时间:2012-10-29 13:16:32

标签: c linux multithreading pthreads mutex

我正在尝试学习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);
    }
}

逻辑是,我要求输入线程在输入可用时处理数据,并通知输出线程打印它。

2 个答案:

答案 0 :(得分:20)

您需要一个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);
        }
    }
}

答案 1 :(得分:10)

您必须在等待之前测试互斥锁下的条件,因为条件变量的信号没有排队(条件变量不是信号量)。也就是说,如果一个线程在该条件变量的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()不能保证它不会虚假地唤醒。使用while ()也意味着发出条件变量的信号始终是完全安全的 - “额外”信号不会影响程序的正确性,这意味着您可以执行诸如将信号移出锁定的代码段之外的操作。