5

在我的 C++ 程序中,我有一个类 CEvent,它带有基于 pthreads 的触发器和等待成员函数(在 Linux 上运行)。如果有一个等待进程,实现是非常明显的(即网上有很多例子)。但是现在我需要满足多个线程正在等待事件的要求,并且在调用 trigger() 时应该全部可靠地唤醒。作为第二个条件,只有在调用 trigger() 时正在等待的线程才应该被唤醒。

我当前的代码:

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);
}

这似乎几乎可以工作,因为在我将 wakeUp 设置回 false 之前等待的所有线程都会唤醒。但是在广播和wakeUp 的重置之间,调用wait() 的其他(或相同)线程也将立即唤醒,这是不可接受的。在 mutext 解锁之前放置 wakeUp = false 可以防止线程唤醒。

我的问题: * pthread_cond_broadcast 何时返回?即有没有保证它只会在所有线程都被唤醒后才返回,或者它可以在之前返回吗?* 这个问题有什么推荐的解决方案吗?

4

1 回答 1

4

请忽略我之前的虚假回答。在触发线程解锁互斥锁(从而释放等待的线程)和设置唤醒值之间存在竞争。这意味着另一个(不等待的)线程可以进来,抓住互斥锁,看到一个真正的值,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);
}
于 2009-05-28T09:29:58.313 回答