我在某处读到我们应该在调用pthread_cond_signal之前锁定互斥锁并在调用它之后解锁互斥锁:
pthread_cond_signal() 例程用于通知(或唤醒)另一个正在等待条件变量的线程。它应该在互斥锁被锁定后调用,并且必须解锁互斥锁才能完成 pthread_cond_wait() 例程。
我的问题是:不锁定互斥体就可以调用pthread_cond_signal或pthread_cond_broadcast方法吗?
我在某处读到我们应该在调用pthread_cond_signal之前锁定互斥锁并在调用它之后解锁互斥锁:
pthread_cond_signal() 例程用于通知(或唤醒)另一个正在等待条件变量的线程。它应该在互斥锁被锁定后调用,并且必须解锁互斥锁才能完成 pthread_cond_wait() 例程。
我的问题是:不锁定互斥体就可以调用pthread_cond_signal或pthread_cond_broadcast方法吗?
如果您没有在更改条件和信号的代码路径中锁定互斥锁,您可能会丢失唤醒。考虑这对过程:
过程一:
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()
,但这可能会导致线程调度的优化程度降低,并且由于条件本身的更改,您必须已将互斥锁锁定在此代码路径中)。
根据本手册:
pthread_cond_broadcast()
orpthread_cond_signal()
函数 可以被线程调用,无论它当前是否拥有线程调用的互斥体或在pthread_cond_wait()
等待pthread_cond_timedwait()
期间与条件变量相关联;但是,如果需要可预测的调度行为,则该互斥锁应由调用pthread_cond_broadcast()
或 的线程锁定pthread_cond_signal()
。
Dave Butenhof(Programming with POSIX Threads的作者)在 comp.programming.threads 上解释了可预测调度行为语句的含义,可在此处获得。
caf,在您的示例代码中,进程 B 进行修改condition
而不首先锁定互斥锁。如果进程 B 只是在修改期间锁定了互斥锁,然后在调用之前仍然解锁了互斥锁pthread_cond_signal
,那么就没有问题 --- 我是对的吗?
我凭直觉相信 caf 的立场是正确的:pthread_cond_signal
在不拥有互斥锁的情况下调用是一个坏主意。但是 caf 的例子实际上并不是支持这一立场的证据;它只是支持弱得多(实际上不言而喻)立场的证据,即除非您首先锁定该互斥锁,否则修改受互斥锁保护的共享状态是一个坏主意。
任何人都可以提供一些示例代码,其中调用pthread_cond_signal
之后会pthread_mutex_unlock
产生正确的行为,但调用pthread_mutex_unlock
之后会pthread_cond_signal
产生不正确的行为?