Почему Boost scoped_lock не разблокирует мьютекс? - PullRequest
12 голосов
/ 10 августа 2009

Я использовал boost::mutex::scoped_lock таким образом:

void ClassName::FunctionName()
{
    {  
     boost::mutex::scoped_lock scopedLock(mutex_);
     //do stuff
      waitBoolean=true;
    }
    while(waitBoolean == true ){
        sleep(1);
    }
    //get on with the thread's activities
}

По сути, он устанавливает waitBoolean, а другой поток сообщает об этом, устанавливая waitBoolean в false;

Однако, похоже, это не работает, потому что другой поток не может заблокировать mutex_ !!

Я предполагал, что, заключив scoped_lock в скобки, я бы прекратил его блокировку. Это не тот случай? Чтение онлайн говорит о том, что оно отказывается от мьютекса только при вызове деструктора. Разве он не будет уничтожен, когда выйдет за пределы этого локального контекста?

Сигнальная часть кода:

while(running_){
   boost::mutex::scoped_lock scopedLock(mutex_);
   //Run some function that need to be done...
   if(waitBoolean){
      waitBoolean=false;
   }
}

Спасибо!

Ответы [ 3 ]

22 голосов
/ 10 августа 2009

Для синхронизации двух потоков используйте условную переменную. Это современный способ синхронизации двух потоков так, как вы хотите:

При использовании boost часть ожидания выглядит примерно так:

void BoostSynchronisationPoint::waitSynchronisation()
{
    boost::unique_lock<boost::mutex> lock(_mutex);

    _synchronisationSent = false;
    while(!_synchronisationSent)
    {
        _condition.wait(lock); // unlock and wait
    }
}

Часть уведомлений выглядит примерно так:

void BoostSynchronisationPoint::sendSynchronisation()
{
    {
        boost::lock_guard<boost::mutex> lock(_mutex);
        _synchronisationSent = true;
    }

    _condition.notify_all();
}

Бизнес с _synchronisationSent состоит в том, чтобы избегать внезапных пробуждений: см. wikipedia

16 голосов
/ 10 августа 2009

scoped_lock действительно должен быть освобожден в конце области. Однако вы не блокируете waitBoolean, когда зацикливаетесь на нем, предлагая не защищать его должным образом и в других местах - например, где для него установлено значение false, и вы в конечном итоге столкнетесь с неприятными условиями гонки.

Я бы сказал, что вы должны использовать boost :: condition_variable, чтобы делать подобные вещи, вместо проверки сна + небезопасных потоков.

0 голосов
/ 31 августа 2012

Также я бы предложил пометить как volatile, что waitBoolean, однако вы должны использовать условие или даже лучше барьер.

...