被 pthread_cond_signal() 唤醒但失去互斥锁竞争的线程会发生什么情况
关于这一点: 如何使用条件变量
假设我们有多个执行此类代码的消费者线程(复制来自引用的页面):
while (TRUE) {
s = pthread_mutex_lock(&mtx);
while (avail == 0) { /* Wait for something to consume */
s = pthread_cond_wait(&cond, &mtx);
}
while (avail > 0) { /* Consume all available units */
avail--;
}
s = pthread_mutex_unlock(&mtx);
}
我假设这里的场景是:主线程调用 pthread_cond_signal() 告诉消费者线程做一些工作。
据我了解 - 后续线程调用 pthread_mutex_lock() 然后调用 pthread_cond_wait() (以原子方式解锁互斥体)。到目前为止,没有一个消费者线程正在声明互斥锁,它们都在 pthread_cond_wait() 上等待。
当主线程调用 pthread_cond_signal() 时,按照 手册页,至少有一个线程被唤醒。当它们中的任何一个从 pthread_cond_wait() 返回时,它会自动声明互斥锁。
所以我的问题是:对于提供的示例代码现在会发生什么? 也就是说,失去互斥体竞争的线程现在会做什么?
(AFAICT 赢得互斥体的线程应该运行其余代码并释放互斥体。失败的线程应该是陷入等待互斥量 - 在第一个 嵌套 while
循环中的某个地方 - 当获胜者持有它并且在它被释放后开始在 pthread_cond_wait() 上阻塞,因为 while (avail == 0)
到那时我就会满意了,对吗?)
Regarding this:
How To Use Condition Variable
Say we have number of consumer threads that execute such code (copied from the referenced page):
while (TRUE) {
s = pthread_mutex_lock(&mtx);
while (avail == 0) { /* Wait for something to consume */
s = pthread_cond_wait(&cond, &mtx);
}
while (avail > 0) { /* Consume all available units */
avail--;
}
s = pthread_mutex_unlock(&mtx);
}
I assume that scenario here is: main thread calls pthread_cond_signal() to tell consumer threads to do some work.
As I understand it - subsequent threads call pthread_mutex_lock() and then pthread_cond_wait() (which atomically unlocks the mutex). By now none of the consumer threads is claiming the mutex, they all wait on pthread_cond_wait().
When the main thread calls pthread_cond_signal(), following the manpage, at least one thread is waken up. When any of them returns from pthread_cond_wait() it automatically claims the mutex.
So my question is: what happens now regarding the provided example code? Namely, what does the thread that lost the contest for the mutex do now?
(AFAICT the thread that won the mutex, should run the rest of the code and release the mutex. The one that lost should be stuck waiting on the mutex - somewhere in the 1st nested while
loop - while the winner holds it and after it's been released start blocking on pthread_cond_wait() beacuse the while (avail == 0)
will be satisfied by then. Am I correct?)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
一旦发出信号/唤醒,
pthread_cond_wait()
必须获取给定的互斥体。如果另一个线程赢得了该竞赛,该函数将阻塞,直到互斥体被释放。因此,从应用程序的角度来看,直到当前线程持有互斥锁才返回。等待始终在循环中完成(上面的while (avail == 0) { ...
),以确保我们正在等待的应用程序条件仍然成立(缓冲区不为空,有更多工作可用等)希望这会有所帮助。
pthread_cond_wait()
has to acquire given mutex once signaled/woken up. If another thread wins that race, the function blocks until the mutex is released. So from the application point of view it doesn't return until current thread holds the mutex. The wait is always done in a loop (while (avail == 0) { ...
above) to make sure that application condition we are waiting for still holds (buffer not empty, more work available, etc.)Hope this helps.
一旦互斥体解锁,输掉比赛的线程就会醒来,再次检查条件,然后在条件变量上休眠。
The thread that lost the contest wakes up once the mutex is unlocked, checks the condition again, then goes to sleep on the condition variable.
啊,但事实并非如此。不是“自动”,也就是说,取决于“自动”的含义。您可能会对 pthread_cond_wait 的“原子”语义感到困惑;但这种语义是在入口端发挥出来的:线程以某种方式注册为在放弃互斥体之前等待条件,因此在任何窗口期间线程不再具有互斥体并且尚未等待在变量上。
从
pthread_cond_wait
返回的每个线程都必须获取互斥体并因此竞争它。那些在互斥锁竞争中失败的人必须阻塞互斥锁,就像它们调用pthread_mutex_lock
一样。从
pthread_cond_wait
退出时获取互斥体的方式可以建模为常规pthread_mutex_lock
操作。本质上,线程必须在互斥体上排队才能退出。每个获取互斥体的线程然后从该函数返回;其他线程必须等到该线程放弃互斥锁才能返回。被信号唤醒的线程不会“自动”获得互斥体,即由于特殊资格而以某种方式转移所有权。首先,在多处理器上,唤醒的线程可能会输掉与已在另一个处理器上运行的线程的竞争,该线程抢夺互斥体(如果可用),或者在接收信号的线程之前排队等待互斥体。其次,调用 pthread_cond_signal 的线程本身可能没有放弃互斥锁,并且可能会无限期地继续持有它,这意味着所有唤醒的线程将在互斥锁操作上排队,并且不会出现任何线程从
pthread_mutex_lock
直到该线程放弃互斥锁。“自动”的全部内容是
pthread_cond_wait
操作在再次获取互斥体之前不会返回,因此应用程序不必执行获取互斥体的步骤。Ah, but it doesn't. Not "automatically", that is, depending on what "automatically" means. You might be confused by the "atomic" semantics of
pthread_cond_wait
; but that semantics is played out on the entry side: a thread is somehow registered for waiting on the condition before giving up the mutex, so that there isn't any window during which the thread no longer has the mutex, and is not yet waiting on the variable.Each thread which returns from
pthread_cond_wait
has to acquire the mutex and therefore contend for it. Those which lose the race for the mutex have to block on the mutex, similarly as if they calledpthread_mutex_lock
.The way the mutex is acquired on exit from
pthread_cond_wait
can be modeled as a regularpthread_mutex_lock
operation. Essentially, the threads have to queue up on the mutex in order to exit. Each thread which acquires the mutex then returns from the function; the others have to wait until that thread gives up the mutex before they are allowed to return.No thread woken up by the signal gets the mutex "automatically", in the sense of somehow being transferred ownership due to special eligibility. Firstly, on a multiprocessor, a woken thread can lose the race to a thread already running on another processor which snatches the mutex, if it is available, or else queue to wait on the mutex ahead of the thread which received the signal. Secondly, the thread which calls
pthread_cond_signal
may itself not have given up the mutex, and may continue to hold it indefinitely, which means that all the woken threads will queue up on a mutex lock operation and none will emerge frompthread_mutex_lock
until that thread gives up the mutex.All that is "automatic" is that the
pthread_cond_wait
operation doesn't return until acquiring the mutex again, and so the application doesn't have to take the step to acquire the mutex.请注意,
pthread_cond_signal()
通常旨在仅唤醒一个等待线程(这就是它所保证的全部)。但它可能会更“意外”地醒来。 while (avail > 0) 循环执行两个功能:它还可以防止出现竞争条件,即在 while (avail > 0) 完成之后、工作线程再次等待该条件之前,工作单元可能已被放入队列中 - 但是竞争也由调用
pthread_cond_wait()
之前的if
测试处理。基本上,当一个线程被唤醒时,它所知道的就是可能有工作单元供其消耗,但也可能没有(另一个线程可能已经消耗了它们)。
因此,调用 pthread_cond_signal() 时发生的事件顺序是:
while (avail > 0)
循环中执行工作,然后Note that
pthread_cond_signal()
is generally intended to wake up only one waiting thread (that's all that it guarantees). But it could wake more 'accidentally'. Thewhile (avail > 0)
loop performs two functions:It also prevents a race condition where a work unit might have been placed on the queue after the
while (avail > 0)
has completed, but before the worker thread has waited on the condition again - but that race is also handled by theif
test just before callingpthread_cond_wait()
.Basically when a thread is awakened, all it knows is that there might be work units for it to consume, but there might not (another thread might have consumed them).
So the sequence of events that occurs when
pthread_cond_signal()
is called is:while (avail > 0)
loop, then will release the mutex