小编典典

为什么 pthread 的条件变量函数需要互斥锁?

all

我正在阅读pthread.h;条件变量相关函数(如pthread_cond_wait(3))需要互斥体作为参数。为什么?据我所知,我将创建一个互斥锁
只是 为了用作该参数?那个互斥锁应该做什么?


阅读 66

收藏
2022-07-06

共1个答案

小编典典

这只是条件变量(或最初)实现的方式。

互斥锁用于保护 条件变量本身 。这就是为什么在等待之前需要将其锁定的原因。

等待将“原子地”解锁互斥锁,允许其他人访问条件变量(用于信号)。然后当条件变量被发送或广播时,等待列表中的一个或多个线程将被唤醒,互斥锁将再次神奇地为该线程锁定。

您通常会看到以下带有条件变量的操作,说明它们是如何工作的。下面的例子是一个工作线程,它通过一个条件变量的信号来工作。

thread:
    initialise.
    lock mutex.
    while thread not told to stop working:
        wait on condvar using mutex.
        if work is available to be done:
            do the work.
    unlock mutex.
    clean up.
    exit thread.

如果等待返回时有一些可用的,则在此循环中完成工作。当线程被标记为停止工作时(通常由另一个线程设置退出条件然后踢条件变量以唤醒该线程),循环将退出,互斥锁将被解锁并且该线程将退出。

上面的代码是一个单消费者模型,因为互斥体在工作完成时保持锁定状态。对于多消费者变体,您可以使用, 例如

thread:
    initialise.
    lock mutex.
    while thread not told to stop working:
        wait on condvar using mutex.
        if work is available to be done:
            copy work to thread local storage.
            unlock mutex.
            do the work.
            lock mutex.
    unlock mutex.
    clean up.
    exit thread.

这允许其他消费者在这个消费者工作时接收工作。

条件变量减轻了您轮询某些条件的负担,而是允许另一个线程在需要发生某些事情时通知您。另一个线程可以告诉该线程该工作可用,如下所示:

lock mutex.
flag work as available.
signal condition variable.
unlock mutex.

通常被错误地称为虚假唤醒的绝大多数通常总是因为在它们的pthread_cond_wait调用(广播)中已发出多个线程的信号,一个线程将返回互斥锁,完成工作,然后重新等待。

然后当没有工作要做时,第二个信号线程可以出来。因此,您必须有一个额外的变量来指示应该完成的工作(这本来就是由 condvar/mutex
对在这里受到互斥保护的——但是,其他线程需要在更改互斥之前锁定互斥)。

从技术上讲 线程可以从条件等待中返回而不会被另一个进程踢(这是一个真正的虚假唤醒),但是,在我从事 pthreads
的所有这些年中,无论是在代码的开发/服务中还是作为用户其中,我从未收到过其中之一。也许这只是因为惠普有一个不错的实施:-)

在任何情况下,处理错误情况的相同代码也处理真正的虚假唤醒,因为不会为这些设置工作可用标志。

2022-07-06