it-roy-ru.com

Попробуй поймать с блокировками в C++

В Java:

Lock lock = new ReentrantLock();
try{
  lock.lock();
  someFunctionLikelyToCauseAnException();
}
catch(e){...}
finally {
  lock.unlock();
}

Мой вопрос в этом примере выше, мы знаем, что блокировка всегда будет разблокирована, потому что, наконец, всегда выполняется, но какова гарантия с C++?

mutex m;
m.lock();
someFunctionLikelyToCauseAnException();
/// ????

Как это будет работать и почему?

37
Brijendar Bakchodia

Для этого мы используем RAII-style construct std::lock_guard . Когда вы используете

std::mutex m;
{ // start of some scope
    std::lock_guard lg(m);
    // stuff
} // end of scope

lg будет гарантировать, что m будет разблокирован независимо от того, по какому пути оставлена ​​область видимости, поскольку она уничтожается при выходе из области видимости, а деструктор std::lock_guards вызовет unlock

Даже если возникнет исключение, стек будет размотан ( разматывание стека ), и этот процесс уничтожит lg, который, в свою очередь, вызовет unlock, гарантируя, что блокировка снята.

61
NathanOliver

что такое гарантия с C++?

Соответствующая гарантия в C++ работает немного иначе, чем та, которую вы упоминаете в Java. Вместо блока finally он полагается на уничтожение автоматических переменных, которое происходит при выходе из области видимости, поскольку кадр стека разматывается. Это разматывание стека происходит независимо от того, как была завершена область действия, изящно или из-за исключения.

Предпочтительный подход для сценария, касающегося таких locks, заключается в использовании RAII , как это реализовано, например, std::lock_guard . Он содержит объект mutex, переданный его конструктору - внутри которого он вызывает метод lock()mutex, после чего поток владеет мьютексом - и при разматывании stack на выходе из области вызывается его деструктор - внутри который вызывает метод mutex's unlock(), освобождая его.

Код будет выглядеть так:

std::mutex m;
{
    std::lock_guard lock(m);
    // Everything here is mutex-protected.
}
// Here you are guaranteed the std::mutex is released.
29
SkepticalEmpiricist

Если во время выполнения фрагмента кода, защищенного критической секцией, возникает исключение, то есть коды между «lock ()» и «unlock ()», это означает, что связанный объект, над которым работает фрагмент кода, больше не является в действительном состоянии. Это, может или не может быть отменено автоматическим разматыванием стека, вызванным исключением, потому что некоторый побочный эффект мог произойти до того, как возникнет исключение (сообщение было отправлено через сокет, машина была началось, например). На данный момент, большая проблема здесь не в том, будет ли освобожден мьютекс (единственная гарантия использования взамен lock_guard). Вполне может быть, что некоторые случаи, когда мьютекс по-прежнему заблокирован, является желательным поведением и может быть явно сброшен после очистки вызывающей стороны от всех ошибок.

Моя точка зрения: это не проблема языка. Никакая языковая функция не может гарантировать правильную обработку ошибок. Не принимайте lock_guard и RAII как серебряную пулю. 

0
John Z. Li