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

CHI*_*HID 17 c linux multithreading mutex pthreads

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

if(cond is false)
   pthread_cond_wait
Run Code Online (Sandbox Code Playgroud)

要么

while(cond is false)
   pthread_cond_wait
Run Code Online (Sandbox Code Playgroud)

我的问题是,我们只想cond_wait因为条件是假的.那么为什么我要明确地设置一个if/while循环的痛苦.我可以理解,在没有任何if/while检查之前cond_wait我们会直接命中它并且它根本不会返回.条件检查仅用于解决此目的还是具有其他意义.如果它用于解决不必要的条件等待,那么进行条件检查并避免使用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Mak*_*zin 21

您需要一个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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


caf*_*caf 12

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

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

pthread_mutex_lock(&m);
cond = true;
pthread_cond_signal(&c);
pthread_mutex_unlock(&m);
Run Code Online (Sandbox Code Playgroud)

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

pthread_mutex_lock(&m);
pthread_cond_wait(&c, &m);
/* cond now true */
Run Code Online (Sandbox Code Playgroud)

这第二个线程将永远阻止.通过让第二个线程检查条件可以避免这种情况:

pthread_mutex_lock(&m);
if (!cond)
    pthread_cond_wait(&c, &m);
/* cond now true */
Run Code Online (Sandbox Code Playgroud)

由于cond仅在m保持互斥锁的情况下进行修改,因此这意味着第二个线程等待且仅当if cond为false时.

一个原因while ()循环矫健的代码,而不是使用的if ()是因为pthread_cond_wait()不能保证它不会醒来不合逻辑.使用a while ()也意味着发出条件变量信号始终是完全安全的 - "额外"信号不会影响程序的正确性,这意味着您可以执行诸如将信号移动到锁定的代码段之外的操作.