3

据我了解,这pthread_cond_t是一个信号对象,类似于 Windows 平台上的事件

所以基本功能pthread_cond_t应该是等待它并发出信号。界面应该如下:

int pthread_cond_wait(pthread_cond_t* cone);
int pthread_cond_singal(pthread_cond_t* cond);

但实际上,pthread_cond_wait需要一个mutex*与其功能没有直接关系的类型参数。所以你需要一个互斥锁,甚至只是想为线程之间的通信创建一个信号,它不会同时访问相同的数据。

那么为什么把界面设计成这样,最终又给用户增加了开销呢?

Edit1: 我知道互斥锁是用来保护条件数据的,但是如果设计没有互斥锁的接口,你也可以通过结合互斥锁和pthread_cond来实现你的目标。而且您也可以只使用pthread_cond来通知它们之间没有共享数据的其他线程。

例如,您可以有一个生产者线程创建文件,完成后通知另一个消费者处理文件,没有数据需要互斥锁保护。

4

2 回答 2

6

条件变量+互斥锁组合中互斥锁的根本原因是为谓词数据提供保护。

请仔细阅读。

条件变量是一种信号机制。就是这样。他们向您发出的信号是您作为服务员已订阅感兴趣的某些外部谓词条件的预期变化。当您最终醒来时,您拥有 mutex,因此拥有谓词数据的专有权利。这是至关重要的。只要所有需要访问谓词数据的线程都按规则运行,并且没有任何线程在不拥有底层互斥锁的情况下以任何方式访问谓词数据,那么一切正常。

对您(应用程序开发人员)来说值得注意并且同样重要的部分:原子地等待条件变量的操作(就您而言,无论如何)开始等待解锁互斥锁以允许其他服务员访问获得它,因此批准访问谓词数据。在 Server 2008 和 Vista 之前,通用 Windows 事件没有这样的东西)。我能描述它在 Windows 上如何工作的最接近的事情是解锁 ahMutex 开始以hEvent原子方式等待 a,从而消除了在两个操作之间潜入更改的可能性。

这是至关重要的,因为它消除了典型的无保护设置和测试的竞争条件。没有原子解锁和等待的所述竞争条件会导致重大问题。例如:您拥有互斥锁,检查数据,而不是您需要的,因此您解锁互斥锁并等待事件。可以想象,在您解锁互斥锁和实际开始等待操作之间,您正在等待的条件发生在那段时间。而你错过了。使用 cvar-mtx 组合正确等待时不会发生这种情况。

最重要的是记住这一点。条件变量并不像您想象的那样保持“状态”。谓词状态保存在您自己设计的数据变量中。保护该状态是关联互斥体的主要工作。您不需要拥有谓词数据互斥体来表示条件更改。但是您确实需要拥有互斥锁才能真正进行更改。如果你不这样做,你就是在玩火。


编辑:鉴于现在已编辑的问题前提(仅没有共享谓词数据的信号机制),我首先不会使用条件变量+互斥锁组合。当需要发送“信号”时,我会使用阻塞管道并向其写入一个字节。而且您不能使用耦合的 cvar+mutex “实体”来设计接口,因为有时您想要更改谓词数据而不是向潜在的服务员发出信号。您可以只锁定互斥锁并在不调用信号的情况下进行更改。如果他们结合在一起,你就不会那么奢侈了。

于 2013-10-24T09:59:05.133 回答
1

你的前提不正确。如果没有受互斥体保护的谓词,您将无法明智地使用条件变量。

例如,您可以有一个生产者线程创建文件,完成后通知另一个消费者处理文件,没有数据需要互斥锁保护。

所以你建议这个:

生产者:
1. 创建文件。
2. 信号条件变量。

消费者:
1. 检查文件。
2. 如果存在,停止。
3.阻塞条件变量。
4. 转到步骤 1。

那是行不通的。如果消费者完成了第 2 步,然后生产者执行了第 1 步和第 2 步怎么办?消费者将进入第 3 步并等待一个永远不会到来的信号。信号没有“保存”,因为条件变量是无状态的。您必须自己维护该状态,并且由于该状态必然是共享的,因此它必须受到互斥体的保护。

一个常见的错误信念pthread_cond_wait是它是有条件的等待。它不是。这是一个无条件的等待条件

于 2014-03-04T13:27:15.213 回答