我在某处读到我们应该在调用 pthread_cond_signal 之前锁定互斥锁并在调用后解锁互斥锁:
pthread_cond_signal()例程是 用来发信号(或唤醒)另一个 正在等待的线程 条件变量。它应该是 在互斥锁被锁定后调用,并且必须 解锁互斥锁以便 pthread_cond_wait()例程到 完整。
我的问题是:是否可以在不锁定互斥锁的情况下调用 pthread_cond_signal 或 pthread_cond_broadcast 方法?
答案 0 :(得分:132)
如果未在代码路径中锁定更改条件和信号的互斥锁,则可能会丢失唤醒。考虑这对过程:
流程A:
pthread_mutex_lock(&mutex);
while (condition == FALSE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
流程B(不正确):
condition = TRUE;
pthread_cond_signal(&cond);
然后考虑这种可能的指令交错,其中condition
以FALSE
开头:
Process A Process B
pthread_mutex_lock(&mutex);
while (condition == FALSE)
condition = TRUE;
pthread_cond_signal(&cond);
pthread_cond_wait(&cond, &mutex);
condition
现在是TRUE
,但是进程A等待条件变量 - 它错过了唤醒信号。如果我们改变进程B来锁定互斥锁:
流程B(正确):
pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
...然后上面就不会发生;唤醒永远不会错过。
(请注意,可以在pthread_cond_signal()
之后实际移动pthread_mutex_unlock()
本身,但这可能导致线程的优化调度不佳,并且您必须锁定由于更改条件本身,mutex已经在此代码路径中。)
答案 1 :(得分:46)
根据本手册:
pthread_cond_broadcast()
或pthread_cond_signal()
功能 可以由线程调用,无论它当前是否拥有互斥锁 调用pthread_cond_wait()
的线程 或pthread_cond_timedwait()
有 与条件变量相关联 在等待期间;但是,如果 可预测的调度行为是 必需的,那个互斥量应该是 由线程调用锁定pthread_cond_broadcast()
或pthread_cond_signal()
。
可预测调度行为语句的含义由Dave Butenhof(Programming with POSIX Threads的作者)解释comp.programming.threads并且可用here。
答案 2 :(得分:4)
caf,在您的示例代码中,进程B修改condition
而不先锁定互斥锁。如果进程B在修改过程中只是锁定了互斥锁,然后在调用pthread_cond_signal
之前仍然解锁了互斥锁,那么就没有问题了 - 我对此是对的吗?
我直觉地认为caf的位置是正确的:在不拥有互斥锁的情况下调用pthread_cond_signal
是一个坏主意。但是,caf的示例实际上并不是支持这一立场的证据;它只是支持弱得多(实际上不言自明)立场的证据,即修改受互斥锁保护的共享状态是一个坏主意,除非你先锁定了这个互斥锁。
任何人都可以提供一些示例代码,其中调用pthread_cond_signal
后跟pthread_mutex_unlock
会产生正确的行为,但调用pthread_mutex_unlock
后跟pthread_cond_signal
会产生错误的行为吗?