In my C++ program I have a class CEvent with trigger and wait member functions based on pthreads (running on Linux). Implementation is quite obvious (i.e. many examples online) if there is one waiting process. However now I need to satisfy the requirement that multiple threads are waiting on the event and should ALL wake up reliably when trigger() is called. As a second condition, only threads that were waiting when trigger() was called should wake up.
My current code:
void CEvent::trigger() {
pthread_mutex_lock(&mutex);
wakeUp = true;
pthread_cond_broadcast(&condition)
pthread_mutex_unlock(&mutex);
wakeUp = false;
}
void CEvent::wait() {
pthread_mutex_lock(&mutex);
while (!wakeUp)
pthread_cond_wait(&condition, &mutex)
pthread_mutex_unlock(&mutex);
}
Run Code Online (Sandbox Code Playgroud)
这似乎几乎可以工作,因为在我将wakeUp 设置回false 之前等待唤醒的所有线程。然而,在广播和唤醒唤醒之间,调用 wait() 的其他(或相同)线程也将立即唤醒,这是不可接受的。在 mutext 解锁之前放置 wakeUp = false 可防止线程唤醒。
我的问题: * pthread_cond_broadcast 何时返回?即是否有保证它只会在所有线程都唤醒后才返回,还是可以在之前返回?* 是否有针对此问题的推荐解决方案?
请无视我之前的虚假回答。触发线程解锁互斥锁(从而释放等待线程)和设置唤醒值之间存在竞争。这意味着另一个(不等待的)线程可以进入,获取互斥体,并在其中看到真值wakeUp并退出,而无需等待。另一个错误是正在等待的线程在wakeUp重置后会被唤醒并立即恢复等待。
解决此问题的一种方法是使用计数 - 每个正在等待的线程都会增加计数,然后触发器将等到许多线程唤醒后再恢复。然后,您必须确保不允许非等待线程开始等待,直到发生这种情况。
// wake up "waiters" count of waiting threads
void CEvent::trigger()
{
pthread_mutex_lock(&mutex);
// wakey wakey
wakeUp = true;
pthread_cond_broadcast(&condition);
// wait for them to awake
while (waiters>0)
pthread_cond_wait(&condition, &mutex);
// stop waking threads up
wakeUp = false;
// let any "other" threads which were ready to start waiting, do so
pthread_cond_broadcast(&condition);
pthread_mutex_unlock(&mutex);
}
// wait for the condition to be notified for us
void CEvent::wait()
{
pthread_mutex_lock(&mutex);
// wait for us to be allowed to start waiting
// we have to wait until any currrently being woken threads have gone
while (wakeUp)
pthread_cond_wait(&condition, &mutex);
// our turn to start waiting
waiters ++;
// waiting
while (!wakeUp)
pthread_cond_wait(&condition, &mutex);
// finished waiting, we were triggered
waiters --;
// let the trigger thread know we're done
pthread_cond_broadcast(&condition);
pthread_mutex_unlock(&mutex);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5338 次 |
| 最近记录: |