2013-10-02 8 views
6

Supponiamo di avere due variabili thread e una variabile di condizione C++ 11 condivisa. cosa succede se la chiamata a thread1 notifica e dopo quella chiamata thread2 attende? sarà thread2 block per sempre o continuerà il lavoro a causa della chiamata di notifica da thread1?Cosa succede se chiamo wait su una variabile di condizione notificata

Edit:

enum bcLockOperation 
{ 
    bcLockOperation_Light = -1, 
    bcLockOperation_Medium = 50, 
    bcLockOperation_Heavy = 1 
} 
class BC_COREDLL_EXP bcCustomMutex 
     { 
     private: 
      bcCustomMutex(const bcCustomMutex&); 
      bcCustomMutex& operator=(const bcCustomMutex&); 

    protected: 
     bcAtomic<int> mFlag; 
     bcMutex mMutex; 
        bcConditionVariable mCond; 

    public: 
     bcCustomMutex() { bcAtomicOperation::bcAtomicInit(mFlag, 0); }; 
     ~bcCustomMutex() {}; 

     /*bcMutex(const bcMutex& pOther) = delete; 
     bcMutex& operator=(const bcMutex& pOther) = delete;*/ 

     bcInline void lock(bcLockOperation pLockOperation = bcLockOperation_Medium) 
     { 
      bcINT32 lNewLoopCount = static_cast<bcINT32>(pLockOperation); 
      bcINT32 lLoopCounter = 0; 
      bcINT32 lExpected = 0; 
      bcINT32 lLoopCount = bcAtomicOperation::bcAtomicLoad(mFlag, bcMemoryOrder_Relaxed); 

      while (true) 
      { 
       while(bcAtomicOperation::bcAtomicLoad(mFlag, bcMemoryOrder_Relaxed) != 0 && 
         lLoopCounter != lLoopCount) 
        ++lLoopCounter; 
       bcAtomicOperation::bcAtomicCompareExchangeStrong(
        mFlag, 
        &lExpected, 
        lNewLoopCount, 
        bcMemoryOrder_Acquire, 
        bcMemoryOrder_Relaxed); 
       if(lExpected == 0) 
       { 
        //mMutex.lock(); 
        return; 
       } 
       else if(lLoopCounter == lLoopCount) 
       { 
        bcLockGuard<bcMutex> lGuard(mMutex); 
              mCond.wait(mMutex); 

       } 
       else 
        continue; 
      } 
     }; 
     bcInline void UnLock() 
     { 
      bcAtomicOperation::bcAtomicStore(mFlag, 0, bcMemoryOrder_Relaxed); 
      bcUniqueLock<bcMutex> lGuard(mMutex); 
          mCond.notifyOne(); 
     }; 
     bcInline bcBOOL TryLock() 
     { 
     }; 
    }; 

Voglio scrivere un mutex personalizzato in modo tale che ogni thread può fornire un argomento che rappresenta la complessità delle operazioni che il thread corrente vuole eseguire. Se la complessità dell'operazione è bassa, gli altri thread si troveranno in un ciclo come un blocco di selezione, ma se la complessità dell'operazione è media, ogni thread eseguirà iterazioni 50 volte e quindi dormirà per variabile di condizione e se l'operazione è molto complessa altri thread andrà a dormire direttamente.

ora supponiamo che thread1 blocchi questo mutex e thread2 va in attesa a causa del suo loopCounter che raggiunge la sua estremità e destra prima di bloccare il mutex della variabile di condizione, chiama thread1 notifica sulla variabile di condizione. Ora thread2 si bloccherà fino a quando un altro thread blocca il mutex personalizzato e quindi le chiamate sbloccano su di esso.

Sono nuovo al multithreading e voglio imparare. So che la mia classe potrebbe contenere errori o potrebbe essere completamente sbagliata, ma esiste un modo per correggere questo problema o un buon algoritmo per scrivere un tale mutex.

Un'altra domanda: le operazioni atomiche sono corrette?

+2

Si può provare da soli, giusto? –

+0

sì hai ragione!ma ho un problema con il mio portatile e lo sto riparando. ora sto pensando al mio problema fino a quando non riesco a scrivere il codice. spiacente – MRB

+0

Non esiste una "variabile di condizione notificata". La cosa più importante da capire sulle variabili di condizione è che sono apolidi. –

risposta

13

Thread2 bloccherà fino a quando qualcuno non chiama. Chiamate per notificare thread di rilascio che sono in attesa al momento della chiamata. Se non ci sono thread in attesa, non fanno nulla. Non sono salvati.

+3

Si noti che questo è il comportamento * contrario * di come funzionano gli eventi su Windows w.r.t 'SetEvent' e' ResetEvent'. –

10

Di solito sia il codice che decide di attendere che il codice che decide di notificare condividono lo stesso mutex. Quindi thread2 non "mancherà" mai la notifica da thread1.

Ecco il classico blocco a base di concurrent esempio coda:

void push(int x) 
{ 
    lock_guard<mutex> guard{queue_mutex}; 
    thequeue.push(x); 
    not_empty_condition.notify_one(); 
} 

int pop() 
{ 
    unique_lock<mutex> guard{queue_mutex}; 
    not_empty_condition.wait(guard, []{ return !thequeue.empty(); }); 
    int x = thequeue.front(); 
    thequeue.pop(); 
    return x; 
} 

Assumere Thread1 e Thread2 sono in esecuzione push() e pop() rispettivamente. Solo uno di loro sarà nella sezione critica alla volta.

  • Se Thread2 ha la serratura, o si aspetta mai perché la coda non è vuota (quindi "perdere" una notifica è innocuo), oppure sta lì in attesa di una notifica (che non sarà persa) .

  • Se thread1 ha ottenuto il blocco, inserisce un elemento nella coda; se thread2 era in attesa, verrà notificato correttamente; se thread2 stava ancora aspettando il mutex, non attenderà mai, poiché c'è almeno un elemento in coda, quindi perdere una notifica è innocuo.

In questo modo, una notifica viene persa solo se non era necessaria in primo luogo.

Ora, se si ha un uso diverso per le variabili di condizione, dove "perdere" una notifica ha qualche conseguenza, credo che si abbia una condizione di competizione o si utilizzi lo strumento sbagliato del tutto.

+0

puoi dare un'occhiata alla mia modifica? Grazie. – MRB

+0

Se vuoi fare una nuova domanda, posta una nuova domanda, non modificare la tua vecchia domanda per cambiare/aggiungere cose non correlate. Inoltre, non posso bcRead lBadly mIndented bAND lIntentionally pObfuscated bcCode. – DanielKO

Problemi correlati