Почему Boost scoped_lock не разблокирует мьютекс?

Я использовал 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;
   }
}

Спасибо!


person Alex    schedule 10.08.2009    source источник
comment
Объект scoped_lock уничтожается в вашей закрывающей скобке, и мьютекс освобождается. Пожалуйста, опубликуйте сигнальную часть кода. Кстати, для ваших нужд лучше использовать boost::condition_variable.   -  person neuro    schedule 10.08.2009
comment
Ну, видя ваш сигнальный код, он может работать в определенных случаях, но зависит от обработки, которую вы выполняете (ваши комментарии). Если есть другой синхро, то хуже. Условная переменная - это способ сделать это. Я разместил код, который использую для такой синхронизации.   -  person neuro    schedule 10.08.2009
comment
Работа сигнального потока больше ничего не блокирует. Он работает независимо.   -  person Alex    schedule 10.08.2009


Ответы (3)


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

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

person nos    schedule 10.08.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 — избежать ложных пробуждений: см. википедию.

person neuro    schedule 10.08.2009

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

person Gaetano Mendola    schedule 31.08.2012