Posix 线程同步原语:pthread_cond_signal() 和 pthread_cond_wait()

Posix Thread Synchronization Primitives: pthread_cond_signal() and pthread_cond_wait()

我正在使用 pthread_cond 结合互斥锁编写多线程代码,这让我想知道:

  1. 是信号一次,所以如果在另一个线程等待之前发送信号,另一个线程会一直等待下去吗?

  2. 因为 cond_wait() 解锁了互斥锁,在 mutex_unlock() 之前写这个语句是否是经验法则,(我意识到这使得后者变得多余,但我这样做只是为了清楚起见)还是有很多场景你想在互斥锁之外编写函数?

将此作为你的口头禅:

Only ever wait for something ...

等待应该几乎总是这样:

if (pthread_mutex_lock(...) != 0) {
    /* something terrible happened, panic */
}

while (test-condition) {
    pthread_cond_wait(...)
}

pthread_mutex_unlock(...)

如果 test-condition 的独占检查失败,因此上下文进入 pthread_cond_wait 关联的互斥体将被自动解锁。

这意味着另一个上下文可以输入如下代码:

if (pthread_mutex_lock(...) != 0) {
    /* panic */
}

test-condition = false;

pthread_cond_signal(...);

pthread_mutex_unlock(...);

更改谓词并自动唤醒调用 pthread_cond_wait 中的第一个上下文,后者又检查谓词 test-condition 并可以跳过循环。

如果我们再看等待代码:

if (pthread_mutex_lock(...) != 0) {
    /* something terrible happened, panic */
}

while (test-condition) {
    pthread_cond_wait(...)
}

pthread_mutex_unlock(...)

在调用等待和解锁之间,始终存在排他性;要么是因为互斥锁是独占获取的(未进入预测的等待循环),要么是因为在 return 从调用 pthread_cond_wait 之前,互斥锁是原子地重新获取的。

同步很难做到正确,而且对于多线程应用程序来说成本很高;人们应该尝试使关键部分保持简单,以将错误的边际压缩到最小尺寸。

另一件重要的事情是检查所有这些 pthread_* 调用的 return 值; return 值是关于状态的重要信息,您始终需要了解它,并且几乎总是需要根据它采取行动。

一些有用的手册页(对于 return 值):