本文介绍了pthreads:关键部分中的pthread_cond_signal()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在线程A中具有以下代码,该代码使用pthread_cond_wait()

I have the following piece of code in thread A, which blocks using pthread_cond_wait()

pthread_mutex_lock(&my_lock);
if ( false == testCondition )
    pthread_cond_wait(&my_wait,&my_lock);
pthread_mutex_unlock(&my_lock);

我在线程B中有以下代码,向线程A发信号

I have the following piece of code in thread B, which signals thread A

pthread_mutex_lock(&my_lock);
testCondition = true;
pthread_cond_signal(&my_wait);
pthread_mutex_unlock(&my_lock);

假设没有其他线程,如果将pthread_cond_signal(&my_wait)移出关键部分代码块,是否会有所不同,如下所示?

Provided there are no other threads, would it make any difference if pthread_cond_signal(&my_wait) is moved out of the critical section block as shown below ?

pthread_mutex_lock(&my_lock);
testCondition = true;
pthread_mutex_unlock(&my_lock);
pthread_cond_signal(&my_wait);

推荐答案

我的建议通常是将pthread_cond_signal()调用保留在锁定区域内,但可能并非出于您的考虑.

My recommendation is typically to keep the pthread_cond_signal() call inside the locked region, but probably not for the reasons you think.

在大多数情况下,是否在未锁定的情况下调用pthread_cond_signal()并不重要. Ben是正确的,如果有另一个线程正在等待,某些调度程序可能会在释放锁定时强制执行上下文切换,因此您的线程可能会在调用pthread_cond_signal()之前被切换掉.另一方面,某些调度程序会在您调用pthread_cond_signal()时立即运行等待线程,因此,如果您在持有锁的情况下调用它,等待线程将醒来然后立即返回睡眠状态(因为现在已被阻塞)互斥体),直到信令线程将其解锁.确切的行为是高度特定于实现的,并且可能会在操作系统版本之间发生变化,因此您不必依赖任何行为.

In most cases, it doesn't really matter whether you call pthread_cond_signal() with the lock held or not. Ben is right that some schedulers may force a context switch when the lock is released if there is another thread waiting, so your thread may get switched away before it can call pthread_cond_signal(). On the other hand, some schedulers will run the waiting thread as soon as you call pthread_cond_signal(), so if you call it with the lock held, the waiting thread will wake up and then go right back to sleep (because it's now blocked on the mutex) until the signaling thread unlocks it. The exact behavior is highly implementation-specific and may change between operating system versions, so it isn't anything you can rely on.

但是,所有这些似乎都超出了您的主要关注范围,即代码的可读性和正确性.通过这种微优化,您不太可能看到任何实际的性能收益(请记住优化的第一条规则:首先进行概要分析,然后进行优化).但是,如果您知道等待线程的集合在设置条件和发送信号的点之间不能改变,那么考虑控制流就容易多了.否则,您必须考虑诸如如果线程A设置testCondition=TRUE并释放锁,然后线程B运行并看到testCondition为真,那么它将跳过pthread_cond_wait()并继续重置testConditionFALSE,然后最终线程A运行并调用pthread_cond_signal(),这将唤醒线程C,因为线程B实际上并没有在等待,但是testCondition不再适用."这会造成混淆,并可能导致代码中难以诊断的竞争条件.出于这个原因,我认为最好发信号通知所持有的锁.这样,您知道设置条件和发送信号相对于彼此是原子的.

But, all of this looks past what should be your primary concern, which is the readability and correctness of your code. You're not likely to see any real-world performance benefit from this kind of micro-optimization (remember the first rule of optimization: profile first, optimize second). However, it's easier to think about the control flow if you know that the set of waiting threads can't change between the point where you set the condition and send the signal. Otherwise, you have to think about things like "what if thread A sets testCondition=TRUE and releases the lock, and then thread B runs and sees that testCondition is true, so it skips the pthread_cond_wait() and goes on to reset testCondition to FALSE, and then finally thread A runs and calls pthread_cond_signal(), which wakes up thread C because thread B wasn't actually waiting, but testCondition isn't true anymore". This is confusing and can lead to hard-to-diagnose race conditions in your code. For that reason, I think it's better to signal with the lock held; that way, you know that setting the condition and sending the signal are atomic with respect to each other.

在相关说明中,您呼叫pthread_cond_wait()的方式不正确.在没有实际发出条件变量的情况下,pthread_cond_wait()可能会返回(尽管很少见),并且在其他情况下(例如,我上面描述的种族),即使条件是没错.为了安全起见,您需要将pthread_cond_wait()调用放在测试条件的while()循环中,以便在重新获取锁后如果不满足条件,则可以调用回pthread_cond_wait().在您的示例中,它看起来像这样:

On a related note, the way you are calling pthread_cond_wait() is incorrect. It's possible (although rare) for pthread_cond_wait() to return without the condition variable actually being signaled, and there are other cases (for example, the race I described above) where a signal could end up awakening a thread even though the condition isn't true. In order to be safe, you need to put the pthread_cond_wait() call inside a while() loop that tests the condition, so that you call back into pthread_cond_wait() if the condition isn't satisfied after you reacquire the lock. In your example it would look like this:

pthread_mutex_lock(&my_lock);
while ( false == testCondition ) {
    pthread_cond_wait(&my_wait,&my_lock);
}
pthread_mutex_unlock(&my_lock);

(我还纠正了您原始示例中的错字,即使用my_mutex代替my_lock来调用pthread_cond_wait().)

(I also corrected what was probably a typo in your original example, which is the use of my_mutex for the pthread_cond_wait() call instead of my_lock.)

这篇关于pthreads:关键部分中的pthread_cond_signal()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 14:39
查看更多