2010-03-04 2 views
24

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

я следующие глобальные переменные:


boost::mutex mutexQ;    // mutex protecting the queue 
boost::mutex mutexCond;   // mutex for the condition variable 
boost::condition_variable condQ; 

Ниже мой поток-потребитель:


void consume() 
{ 
    while(!bStop) // globally declared, stops when ESC key is pressed 
    { 
     boost::unique_lock lock(mutexCond); 
     while(!bDataReady) 
     { 
      condQ.wait(lock); 
     } 

     // Process data 
     if(!messageQ.empty()) 
     { 
      boost::mutex::scoped_lock lock(mutexQ); 

      string s = messageQ.front(); 
      messageQ.pop(); 
     } 
    } 
} 

Ниже мой продюсер Тема:


void produce() 
{ 
    int i = 0; 

    while((!bStop) && (i < MESSAGE)) // MESSAGE currently set to 10 
    { 
     stringstream out; 
     out << i; 
     string s = out.str(); 

     boost::mutex::scoped_lock lock(mutexQ); 
     messageQ.push(s); 

     i++; 
     { 
      boost::lock_guard lock(mutexCond); // HANGS here 
      bDataReady = true; 
     } 
     condQ.notify_one(); 
    } 
} 
+6

FWIW, эта ошибка является прекрасным примером «блокировки инверсии». В одном потоке вы сначала блокируете mutexQ, а затем, не отпуская его, вы блокируете mutexCond. В другом потоке вы сначала блокируете mutexCond, а затем mutexQ. Это почти всегда неправильно. Один поток получает один замок, а другой - другой. Тогда они оба будут ждать, чтобы получить замок, которого у них нет. Которые они не могут получить, когда-либо. Простые решения - либо использовать меньшее количество блокировок (что в любом случае является правильным, даже если это не для инверсии), либо определить «иерархию» блокировок, поэтому вы всегда можете принимать их в последовательном порядке. –

ответ

34

Вы должны использовать тот же mutex для защиты очереди, как вы используете в переменной условия.

Это должно быть все, что вам нужно:

void consume() 
{ 
    while(!bStop) 
    { 
     boost::scoped_lock lock(mutexQ); 
     // Process data 
     while(messageQ.empty()) // while - to guard agains spurious wakeups 
     { 
      condQ.wait(lock); 

     } 
     string s = messageQ.front();    
     messageQ.pop(); 
    } 
} 

void produce() 
{ 
    int i = 0; 

    while((!bStop) && (i < MESSAGE)) 
    { 
     stringstream out; 
     out << i; 
     string s = out.str(); 

     boost::mutex::scoped_lock lock(mutexQ); 
     messageQ.push(s); 
     i++; 
     condQ.notify_one(); 
    } 
} 
+0

@nos: Спасибо, ваше решение сработало. Это наиболее распространенное приложение/использование переменных условия, правильно? – jasonline

+0

«// в то время как - для защиты повторных побочных пробуждений» Не могли бы вы объяснить, почему нужен цикл while. Означает ли это, что wait() может вернуться без указания производителем? – Haider

+0

@ Хаидер В некоторых случаях да - хотя, вероятно, не в этом маленьком примере. Они несколько объясняются здесь http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_cond_wait.html, это pthreads, а не boost, но boost on * nixes использует pthreads и не может реально принимать какие-либо меры против него. С помощью while() вместо if() проще изменить код на несколько пользователей, и в этом случае вы в конечном итоге сделаете правильную вещь, если другой потребитель захватит это значение до того, как вы это сделаете. (Если у вас несколько потребителей, condQ.notify_one() может просыпать более одного из них) – nos

Смежные вопросы