首页 文章

为什么围绕pthread等待条件需要while循环?

提问于
浏览
49

我正在学习pthread和等待条件 . 据我所知,一个典型的等待线程是这样的:

pthread_mutex_lock(&m);
while(!condition)
     pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

我无法理解的是,即使我使用 pthread_cond_signal() 来唤醒线程,为什么行 while(!condition) 是必要的 .

我可以理解,如果我使用 pthread_cond_broadcast() 我需要测试条件,因为我唤醒所有等待的线程,其中一个可以在解锁互斥锁之前再次使条件为假(从而将执行转移到另一个不应该执行的唤醒线程那一点) . 但是如果我使用 pthread_cond_signal() 我只唤醒一个线程,所以条件必须为真 . 所以代码看起来像这样:

pthread_mutex_lock(&m);
pthread_cond_wait(&cond, &m);
// Thread stuff here
pthread_mutex_unlock(&m);

我读到了一些可能发生的虚假信号 . 这是(也是唯一的)原因吗?我为什么要有虚假的信号呢?或者还有其他我没有得到的东西?

我假设信号代码是这样的:

pthread_mutex_lock(&m);
condition = true;
pthread_cond_signal(&cond); // Should wake up *one* thread
pthread_mutex_unlock(&m);

2 回答

  • 16

    你应该将pthread_cond_wait放在while循环中的真正原因不是因为虚假的唤醒 . 即使您的条件变量没有虚假唤醒,您仍然需要循环来捕获常见类型的错误 . 为什么?考虑如果多个线程在相同条件下等待会发生什么:

    Thread 1                         Thread 2           Thread 3
    check condition (fails)
    (in cond_wait) unlock mutex
    (in cond_wait) wait
                                     lock mutex
                                     set condition
                                     signal condvar
                                     unlock mutex
                                                        lock mutex
                                                        check condition (succeeds)
                                                        do stuff
                                                        unset condition
                                                        unlock mutex
    (in cond_wait) wake up
    (in cond_wait) lock mutex
    <thread is awake, but condition
    is unset>
    

    这里的问题是线程必须在等待之前释放互斥锁,否则可能允许另一个线程“窃取”该线程正在等待的任何内容 . 除非保证只有一个线程可以在该条件下等待,否则假设线程唤醒时条件有效是不正确的 .

  • 46

    假设您没有检查条件 . 然后通常你无法避免发生以下不好的事情(至少,你不能在一行代码中避免它):

    Sender                             Receiver
    locks mutex
    sets condition
    signals condvar, but nothing 
      is waiting so has no effect
    releases mutex
                                        locks mutex
                                        waits. Forever.
    

    当然,您的第二个代码示例可以通过执行以下操作来避

    pthread_mutex_lock(&m);
    if (!condition) pthread_cond_wait(&cond, &m);
    // Thread stuff here
    pthread_mutex_unlock(&m);
    

    那么肯定是这样的情况:如果只有一个接收器,并且 cond_signal 是唯一可以将其唤醒的东西,那么它只会在条件设置时唤醒,因此不需要循环 . nos涵盖了为什么第二个"if"不正确 .

相关问题