2015-11-25 9 views
9

К try_lock*, я беру в расчет try_lock(), try_lock_for() и try_lock_until(). Согласно cppreference, все три метода могут просто проиграть ложно. Ниже приводится цитата из описания для try_lock_for()std :: timed_mutex :: try_lock * fail spuriously

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

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

ответ

16

По: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3209.htm

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

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

От C++ 14 главе "30.4.1.2 типы Mutex"

пункт 16:

Реализация может не получить блокировку, даже если он не принадлежит какой-либо другой поток. [Примечание. Этот ложный сбой обычно необычен, но позволяет интересные реализации на основе простого сравнения и обмена (статья 29). -end note] Реализация должна гарантировать, что 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 

 Смежные вопросы

  • Нет связанных вопросов^_^