2015-11-25 12 views
9

Per try_lock*, intendo per try_lock(), try_lock_for() e try_lock_until(). Secondo lo cppreference, tutti e tre i metodi potrebbero semplicemente fallire spurio. Di seguito viene indicata dalla descrizione per try_lock_for()std :: timed_mutex :: try_lock * fail spurio

Come try_lock(), questa funzione viene lasciata fallire spurio e ritorno false anche se il mutex non è stata bloccata da qualsiasi altro filo ad certo punto durante timeout_duration.

So che la sveglia spuria può accadere con std::condition_variable e la logica dietro di esso. Ma, che succede con un mutex?

risposta

16

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

D'altra parte, ci sono ragioni forti per richiedere che i programmi di essere scritti a tollerare try_lock spurio() fallimenti:

  1. Come sottolineato in Boehm, Adve , "Fondamenti del modello di memoria concorrente C++", PLDI 08, rafforzando la coerenza sequenziale per i programmi privi di dati senza errori spuri try_lock() richiede un ordine di memoria significativamente più forte per le operazioni lock() su try_lock() - tipi di mutex compatibili. Su alcune architetture che aumenta in modo significativo il costo delle acquisizioni di mutex non controversi. Questo costo sembra superare di gran lunga qualsiasi beneficio derivante dal proibire errori spuri try_lock().
  2. Consente a un try_lock() scritto dall'utente di fallire se, ad esempio, l'implementazione non riesce ad acquisire un blocco di basso livello utilizzato per proteggere la struttura dati mutex. O permette che una tale operazione sia scritta direttamente in termini di compare_exchange_weak.
  3. Assicura che il codice client rimanga corretto quando, ad esempio, viene introdotto un thread di debug che occasionalmente acquisisce blocchi per essere in grado di leggere i valori coerenti da una struttura dati controllata o esaminata. Qualsiasi codice che ottiene informazioni dall'errore try_lock() si interromperà con l'introduzione di un altro thread che blocca e legge semplicemente la struttura dei dati.
5

Da C++ 14 capitolo "30.4.1.2 tipi mutex"

paragrafo 16:

Un'implementazione potrebbe non riuscire a ottenere il blocco, anche se non è detenuto da qualsiasi altro thread. [Nota: questo errore spuria è normalmente raro, ma consente implementazioni interessanti basate su un semplice confronto e scambio (clausola 29). -end note] Un'implementazione dovrebbe garantire che try_lock() non restituisca in modo coerente false in assenza di acquisizioni di mutex in conflitto.

e il paragrafo 19:

poco sarebbe stato conosciuto circa lo stato dopo un guasto, anche in assenza di guasti spuri

E in risposta a

So che può accadere che la sveglia spuria avvenga con std :: condition_variable e la logica dietro di esso. Ma, che succede con un mutex?

std::timed_mutex a volte viene implementato utilizzando std::condition_varible quando non esiste un supporto diretto nel sistema operativo. Come in 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