原文是stackoverflow
上的一篇问答,地址如下:
Why do pthreads’ condition variable functions require a mutex?
问题描述
我正在读pthread.h
;跟条件变量(condition variable)有关的函数(如pthread_cond_wait(3)
)需要一个互斥量(mutex)作为参数。为什么?就我看来,我建一
个互斥量就是为了当作参数用?这个互斥量的作用是什么?
paxdiablo 的回答
其实条件变量就是这样实现的。
互斥量是用来保护条件变量的。这就是你需要在做 wait 操作之前上锁的原因。
wait 操作会“自动”解锁 mutex,以使得其他线程可以使用条件变量(来发送信号)。当条
件变量收到信号或广播时,一个或多个在等待列表里的线程就会被唤醒,而互斥量将会神奇
地为那个线程上锁。
你一般会看到对条件变量进行如下操作来展示他们怎么工作。下面的例子是一个工作线程,
它借由环境变量收到信号的方式来接收工作。
1 | thread: |
当有工作可以做时 wait 返回,然后在循环里进行处理。当线程被告知要停止工作时(一般
是由另一个线程设置退出变量,然后设置环境变量来唤醒该进程),循环退出,mutex 被解
锁然后线程退出。
以上代码是单个消费者模型,其中在工作被处理时互斥量仍然处于上锁状态。对于多消费者
模型来说,你可以用下面的例子:
1 | thread: |
这使得在该线程处理任务的同时其他消费者可以接受任务。
条件变量帮你免除了需要轮询某些状态的负担,取而代之的是让另一线程在需要进行工作时
通知你。那个进程可以用以下的方式通知有有工作可做:
1 | lock mutex. |
大部分被错误地称作虚假唤醒的现象通常是因为多个线程在pthread_cond_wait
中被信号
(或者广播)唤醒,但只有一个能对互斥量上锁,然后处理任务,最后再进入等待。
而其他被唤醒的线程发现没有工作可做。所以你不得不有一个额外的变量来表明有工作可以
做(这就是互斥量需要保护的,其他线程在改变它的值之前必须先把互斥量上锁)。
理论上,一个线程在没有被其他进程唤醒的情况下是有可能从 wait 状态中醒来的(这就是
纯粹的虚假唤醒),但在我做与 pthread 相关工作的这么多年里,无论是开发还是使用它,
我一次都没有遇到过这种情况。或许那只是因为 HP 有一个好的实现吧 :-)
无论怎么,能够处理错误情况的代码也能处理虚假唤醒的情况,因为工作可做标志不会因为
这些而被设置。