std :: timed_mutex :: try_lock * внезапно терпит неудачу

От try_lock*Я имею в виду try_lock(), try_lock_for(), а также try_lock_until(), В соответствии с cppreference, все три метода могут просто сбои. Ниже приводится цитата из описания для try_lock_for()

Как с try_lock()эта функция допускает случайный сбой и
вернуть false даже если мьютекс не был заблокирован каким-либо другим потоком в
какой-то момент во время timeout_duration,

Я знаю, что ложное пробуждение может произойти с std::condition_variable и обоснование этого. Но как обстоят дела с мьютексом?

10

Решение

В соответствии с: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3209.htm

С другой стороны, существуют веские причины требовать, чтобы программы были написаны так, чтобы они допускали ложные сбои try_lock ():

  1. Как указывает Бем, Adve, «Основы модели памяти параллелизма C ++», PLDI 08, для обеспечения последовательной согласованности для программ без данных и без ложных сбоев try_lock () требуется значительно более строгий порядок памяти для операций lock () в try_lock ( ) -совместимые типы мьютексов. На некоторых архитектурах это значительно увеличивает стоимость необоснованных приобретений мьютекса. Эта стоимость, по-видимому, значительно перевешивает любую выгоду от запрета ложных сбоев try_lock ().
  2. Это позволяет написанному пользователем try_lock () потерпеть неудачу, если, например, реализации не удается получить низкоуровневую блокировку, используемую для защиты структуры данных мьютекса. Или это позволяет писать такую ​​операцию напрямую в терминах compare_exchange_weak.
  3. Это гарантирует, что клиентский код остается корректным, когда, например, вводится поток отладки, который иногда получает блокировки, чтобы иметь возможность считывать согласованные значения из проверяемой или проверяемой структуры данных. Любой код, который получает информацию о сбое try_lock (), прервется с введением другого потока, который просто блокирует и считывает структуру данных.
16

Другие решения

Из главы 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
5

По вопросам рекламы [email protected]