基于pthread的事件只唤醒等待线程

时间:2009-05-28 08:52:45

标签: events pthreads

在我的C ++程序中,我有一个类CEvent,带有基于pthreads的触发器和等待成员函数(在Linux上运行)。如果有一个等待过程,则实施非常明显(即在线的许多示例)。但是现在我需要满足多个线程正在等待事件的要求,并且当调用trigger()时,ALL应该可靠地唤醒。作为第二个条件,只有在调用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()的其他(或相同)线程也将立即唤醒,这是不可接受的。在静音解锁之前放置wakeUp = false可以防止线程被唤醒。

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

1 个答案:

答案 0 :(得分:3)

请忽略我之前的虚假答案。触发器线程解锁互斥锁的时间(从而释放等待的线程)之间存在竞争,然后设置wakeUp值。这意味着可以进入另一个(不等待)线程,获取互斥锁,并在wakeUp中查看真值并在不等待的情况下退出。另一个错误是,正在等待的线程将在wakeUp重置后立即唤醒并立即恢复等待。

解决此问题的一种方法是使用count - 每个等待的线程将递增计数,然后触发器将等待,直到许多线程在恢复之前已经唤醒。然后,您必须确保不允许非等待的线程开始等待,直到发生这种情况。

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