От try_lock*
Я имею в виду try_lock()
, try_lock_for()
, а также try_lock_until()
, В соответствии с cppreference, все три метода могут просто сбои. Ниже приводится цитата из описания для try_lock_for()
Как с
try_lock()
эта функция допускает случайный сбой и
вернутьfalse
даже если мьютекс не был заблокирован каким-либо другим потоком в
какой-то момент во времяtimeout_duration
,
Я знаю, что ложное пробуждение может произойти с std::condition_variable
и обоснование этого. Но как обстоят дела с мьютексом?
В соответствии с: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3209.htm
С другой стороны, существуют веские причины требовать, чтобы программы были написаны так, чтобы они допускали ложные сбои try_lock ():
- Как указывает Бем, Adve, «Основы модели памяти параллелизма C ++», PLDI 08, для обеспечения последовательной согласованности для программ без данных и без ложных сбоев try_lock () требуется значительно более строгий порядок памяти для операций lock () в try_lock ( ) -совместимые типы мьютексов. На некоторых архитектурах это значительно увеличивает стоимость необоснованных приобретений мьютекса. Эта стоимость, по-видимому, значительно перевешивает любую выгоду от запрета ложных сбоев try_lock ().
- Это позволяет написанному пользователем try_lock () потерпеть неудачу, если, например, реализации не удается получить низкоуровневую блокировку, используемую для защиты структуры данных мьютекса. Или это позволяет писать такую операцию напрямую в терминах compare_exchange_weak.
- Это гарантирует, что клиентский код остается корректным, когда, например, вводится поток отладки, который иногда получает блокировки, чтобы иметь возможность считывать согласованные значения из проверяемой или проверяемой структуры данных. Любой код, который получает информацию о сбое try_lock (), прервется с введением другого потока, который просто блокирует и считывает структуру данных.
Из главы C ++ 14 «30.4.1.2 Типы мьютекса»
пункт 16:
Реализация может не получить блокировку, даже если она не удерживается каким-либо другим потоком. [Примечание: этот ложный сбой, как правило, встречается редко, но допускает интересные реализации на основе простого сравнения и обмена (раздел 29). — примечание] Реализация должна обеспечивать
try_lock()
не всегда возвращаетсяfalse
при отсутствии оспаривающих мьютекс приобретений.
и пункт 19:
мало что будет известно о состоянии после сбоя, даже при отсутствии ложных сбоев
И в ответ на
Я знаю, что ложное пробуждение может произойти с std :: condition_variable
и обоснование этого. Но как обстоят дела с мьютексом?
std::timed_mutex
иногда реализуется с помощью std::condition_varible
когда нет прямой поддержки в ОС. Как и в GNU libstdc ++:
#if _GTHREAD_USE_MUTEX_TIMEDLOCK
...
#else // !_GTHREAD_USE_MUTEX_TIMEDLOCK
class timed_mutex
{
mutex _M_mut;
condition_variable _M_cv;
bool _M_locked = false;
public:
template<typename _Rep, typename _Period>
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{
unique_lock<mutex> __lk(_M_mut);
if (!_M_cv.wait_for(__lk, __rtime, [&]{ return !_M_locked; }))
return false;
_M_locked = true;
return true;
}
template<typename _Clock, typename _Duration>
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
unique_lock<mutex> __lk(_M_mut);
if (!_M_cv.wait_until(__lk, __atime, [&]{ return !_M_locked; }))
return false;
_M_locked = true;
return true;
}
};
#endif