在不锁定互斥锁的情况下调用pthread_cond_signal

时间:2010-12-28 06:52:36

标签: c++ pthreads mutex signals condition-variable

我在某处读到我们应该在调用 pthread_cond_signal 之前锁定互斥锁并在调用后解锁互斥锁:

  

pthread_cond_signal()例程是   用来发信号(或唤醒)另一个   正在等待的线程   条件变量。它应该是   在互斥锁被锁定后调用,并且必须   解锁互斥锁以便   pthread_cond_wait()例程到   完整。

我的问题是:是否可以在不锁定互斥锁的情况下调用 pthread_cond_signal pthread_cond_broadcast 方法?

3 个答案:

答案 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);

然后考虑这种可能的指令交错,其中conditionFALSE开头:

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会产生错误的行为吗?