pthread_cond_wait не просыпается от pthread_cond_broadcast - PullRequest
2 голосов
/ 07 апреля 2011

в моей программе есть часть кода, которая ожидает пробуждения от другой части кода:
Вот часть, которая ложится спать:

void flush2device(int task_id) {

if (pthread_mutex_lock(&id2cvLock) != SUCCESS) {
    cerr << "system error - exiting!!!\n";
    exit(1);
}

map<int,pthread_cond_t*>::iterator it;

it = id2cv.find(task_id);

if(it == id2cv.end()){

    if (pthread_mutex_unlock(&id2cvLock) != SUCCESS) {
        cerr << "system error\n UNLOCKING MUTEX flush2device\n"; 
        exit(1);
    }

    return;
}

cout << "Waiting for CV signal" <<endl;

if(pthread_cond_wait(it->second, &id2cvLock)!=SUCCESS){
    cerr << "system error\n COND_WAIT flush2device - exiting!!!\n";
    exit(1);
}
cout << "should be right after " << task_id << " signal" << endl;


if (pthread_mutex_unlock(&id2cvLock) != SUCCESS) {
    cerr << "system error\n UNLOCKING MUTEX flush2device -exiting!!!\n"; 
    exit(1);
}

}
В другой части кода есть просыпающаяся часть (сигнализация):

//id2cv is a map <int, pthread_cond_t*> variable. - the value is a pointer to the cv on
//which we call with the broadcast method.
if(pthread_mutex_lock(&id2cvLock)!=SUCCESS){
    cerr <<"system error\n";
    exit(1);
}

id2cv.erase(nextBuf->_taskID);

cout << "In Thread b4 signal, i'm tID " <<nextBuf->_taskID << endl;
    if (pthread_cond_broadcast(nextBuf->cv) != 0) {
        cerr << "system error SIGNAL_CV doThreads\n";
        exit(1);
    }
cout << "In doThread, after erasing id2cv " << endl;
if(pthread_mutex_unlock(&id2cvLock)!=SUCCESS){
    cerr <<"system error\n;
    exit(1);
}  

Большинство рабочих процессов работают просто отлично, но время от времени программа просто перестает «реагировать» - первый метод (см. Выше) просто не пропускает часть cond_wait - похоже, никто на самом деле не посылает ей сигнал на время (или по какой-то другой причине) - пока другой метод (частью которого является последняя часть кода) продолжает работать.

Где я ошибаюсь в логике мьютексов и сигнализации? Я уже проверил, что переменная pthread_cond_t все еще "жива" до вызова метода cond_wait и cond_broadcast, и ничего в этой области не является ошибкой.

Ответы [ 3 ]

5 голосов
/ 17 сентября 2011

Несмотря на название, pthread_cond_wait является условным un условным ожиданием для условия. Вы не должны звонить pthread_cond_wait, если вы не подтвердили, что есть что-то, что нужно ждать, и то, что его ждет, должно быть защищено соответствующим мьютексом.

Переменные состояния не имеют состояния, и приложение должно хранить состояние ожидаемой вещи, называемой «предикатом».

Канонический рисунок:

pthread_mutex_lock(&mutex);
while(!ready_for_me_to_do_something)
   pthread_cond_wait(&condvar, &mutex);
do_stuff();
ready_for_me_to_do_something=false; // this may or may not be appropriate    
pthread_mutex_unlock(&mutex);

и

pthread_mutex_lock(&mutex);
ready_for_me_to_do_something=true;
pthread_cond_broadcast(&condvar);
pthread_mutex_unlock(&mutex);

Обратите внимание, как этот код поддерживает состояние в переменной ready_for_me_to_do_something, и ожидающий поток ожидает в цикле, пока эта переменная не станет true. Обратите внимание, как мьютекс защищает эту разделяемую переменную и защищает условную переменную (потому что она также разделяется между потоками).

Это не единственный правильный способ использования условной переменной, но очень легко столкнуться с проблемами при любом другом использовании. Вы звоните pthread_cond_wait, даже если нет причин ждать. Если вы ждете, пока ваша сестра вернется домой с машиной, прежде чем использовать ее, а она уже вернулась, вы будете ждать долго.

2 голосов
/ 15 апреля 2011

Ваше использование pthread_cond_wait() неверно.Если переменная условия сигнализируется в то время, когда ни один процесс не ожидает, сигнал не имеет никакого эффекта.Он не сохраняется в следующий раз, когда процесс ожидает.Это означает, что правильное использование pthread_cond_wait() выглядит следующим образом:

pthread_mutex_lock(&mutex);
/* ... */
while (!should_wake_up)
    pthread_cond_wait(&cond, &mutex);

Условие should_wake_up может быть просто простой проверкой переменной флага, или это может быть что-то вроде более сложной проверки для буферабыть пустым или полным, или что-то подобное.Мьютекс должен быть заблокирован для защиты от одновременных модификаций, которые могут изменить результат should_wake_up.

Неясно, каким должен быть этот тест в вашей программе - вам может потребоваться добавить определенную переменную-флаг.

0 голосов
/ 07 апреля 2011

Я не думаю, что в части "пробуждения" достаточно кода, но мое первоначальное предположение состоит в том, что pthread_cond_wait не было введено во время выдачи pthread_cond_broadcast.

Другая возможность состоит в том, что pthread_cond_wait находится в середине ложного пробуждения и полностью пропускает сигнал.

Я почти уверен, что в большинстве случаев использования условных переменных также есть внешний предикат, который необходимо проверять после каждого пробуждения, чтобы узнать, есть ли работа, которую нужно сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...