在不locking互斥锁的情况下调用pthread_cond_signal
我读了一个地方,我们应该在调用pthread_cond_signal之前locking互斥锁 ,并在调用它之后解锁互斥锁 :
pthread_cond_signal()例程用于发送(或唤醒)等待条件variables的另一个线程。 它应该在locking互斥锁之后调用,并且必须解锁互斥锁才能完成pthread_cond_wait()例程。
我的问题是:是不是可以调用pthread_cond_signal或pthread_cond_broadcast方法而不locking互斥锁?
如果您不locking代码path中的互斥锁,这会改变条件和信号,则可能会失去唤醒。 考虑这一对过程:
过程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停留在等待条件variables – 它错过了唤醒信号。 如果我们改变进程B来locking互斥锁:
过程B(正确):
pthread_mutex_lock(&mutex); condition = TRUE; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex);
…那么上面不会发生; 唤醒将永远不会被错过。
(请注意,实际上可以在pthread_cond_signal()
之后移动pthread_cond_signal()
本身,但是这可能导致线程的优化调度较less,并且由于更改了条件本身,您必须locking此代码path中已有的互斥锁)。
根据这本手册:
线程可以调用
pthread_cond_broadcast()
或pthread_cond_signal()
函数,不pipe它是否当前拥有调用pthread_cond_wait()
或pthread_cond_timedwait()
线程在等待期间与条件variables相关联的互斥锁 ; 然而,如果需要可预测的调度行为,则该线程将被调用pthread_cond_broadcast()
或pthread_cond_signal()
的线程locking。
可预测的调度行为语句的含义由comp.programming.threads上的Dave Butenhof( 编程使用POSIX线程的作者)解释,可在此处find 。
caf,在您的示例代码中,进程B修改condition
而不先locking互斥锁。 如果进程B在修改过程中简单地locking了互斥锁,然后在调用pthread_cond_signal
之前仍然解锁了互斥锁,那么就没有问题了 – 我是对的吗?
我直觉地认为,咖啡的位置是正确的:调用pthread_cond_signal
而不拥有互斥锁是一个坏主意。 但是caf的例子实际上并不支持这一立场。 它只是支持更弱(实际上不言而喻)的立场的证据,除非您先locking了互斥体,否则修改由互斥体保护的共享状态是一个不好的想法。
任何人都可以提供一些示例代码,其中调用pthread_cond_signal
紧接着pthread_mutex_unlock
产生正确的行为,但调用pthread_mutex_unlock
紧接着pthread_cond_signal
产生不正确的行为?