2009-05-28 5 views
3

В моей программе на C++ у меня есть класс CEvent с функциями запуска триггера и ожидания, основанный на pthreads (работает в Linux). Реализация довольно очевидна (т. Е. Много примеров в Интернете), если есть один процесс ожидания. Однако теперь мне нужно выполнить требование о том, что на событие ожидаются несколько потоков, и ВСЕ ДОЛЖНО просыпаться с надежностью при вызове trigger(). В качестве второго условия должны появляться только те потоки, которые ожидали, когда вызывался trigger().событие pthread пробуждение только ожидающих потоков

Мой текущий код:

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 другие (или те же) потоки, вызывающие wait(), также сразу просыпаются, что неприемлемо. Помещение wakeUp = false перед разблокировкой mutext предотвращает пробуждение потоков.

Мои вопросы: * Когда возвращается pthread_cond_broadcast? То есть есть ли гарантия, что он вернется только после того, как все потоки проснулись или могли бы вернуться раньше? * Есть ли рекомендованные решения этой проблемы?

ответ

3

Пожалуйста, не обращайте внимания на мой предыдущий фиктивный ответ. Между временем, когда триггерный поток разблокирует мьютексы (и, таким образом, освобождает ожидающие потоки), происходит гонка, а затем устанавливается значение wakeUp. Это означает, что другой (не ожидающий) поток может войти, захватить мьютекс и увидеть истинное значение в 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); 
} 
+0

Спасибо, это похоже на трюк. – 2009-05-28 12:53:09