2013-10-02 19 views
6

Załóżmy, że mam dwie zmienne warunkowe z wątkiem i jedną wspólną. co się stanie, jeśli wywołanie wątku1 powiadomi i po tym wywołaniu wątku2 zaczekać? will thread2 block forever lub będzie kontynuować pracę z powodu wywołania notify przez thread1?Co się stanie, jeśli zadzwonię wait na zmienną warunku powiadomienia

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() 
     { 
     }; 
    }; 

Chcę napisać niestandardowy mutex tak, że każdy wątek może stanowić argumentu, który reprezentuje złożoność operacji, że obecny wątek chce wykonać. Jeśli złożoność operacji jest niska, inne wątki będą w pętli jak blokada spin, ale jeśli złożoność operacji jest średnia, każdy wątek będzie iterować 50 razy, a następnie będzie przespacerował się przez zmienną warunku, a jeśli operacja jest bardzo złożona, inne wątki natychmiast pójdzie spać.

teraz załóżmy, że wątek1 blokuje ten muteks, a wątek2 przechodzi do oczekiwania z powodu osiągnięcia przez pętlęCounter jej końca i tuż przed zablokowaniem muteksu zmiennej warunkowej, wywołania thread1 powiadamiają o zmiennej warunku. Teraz wątek 2 będzie uśpiony, dopóki inny wątek nie zablokuje niestandardowego muteksu, a następnie wywoła na nim odblokowanie.

Jestem nowy w wielowątkowości i chcę się uczyć. Wiem, że moja klasa może zawierać błędy lub może być całkowicie błędna, ale czy jest jakiś sposób na naprawienie tego problemu lub dobry algorytm do napisania takiego muteksu.

Kolejne pytanie: Czy moja operacja atomowa jest poprawnie zamawiana?

+2

Możesz spróbować sam, prawda? –

+0

Tak, masz rację!ale mam problem z moim laptopem i naprawiam go. teraz myślę o moim problemie, dopóki nie będę mógł napisać kodu. przepraszam – MRB

+0

Nie ma czegoś takiego jak "powiadomiona zmienna warunku". Najważniejszą rzeczą do zrozumienia zmiennych warunkowych jest to, że są bezpaństwowcami. –

Odpowiedz

13

Wątek2 zablokuje do momentu, aż ktoś zadzwoni powiadomić. Połączenia do powiadomienia o zwalnianiu wątków oczekujących w czasie połączenia. Jeśli nic nie czeka, nic nie robią. Nie są zapisane.

+3

Należy zauważyć, że jest to * przeciwne * zachowanie działania zdarzeń w systemie Windows w.r.t 'SetEvent' i' ResetEvent'. –

10

Zwykle zarówno kod, który decyduje się czekać, jak i kod, który decyduje się powiadomić, mają ten sam muteks. Tak więc thread2 nigdy nie "przegapi" powiadomienia z wątku1.

Oto klasyczny zamek oparte współbieżne przykład kolejka:

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; 
} 

Załóżmy thread1 i thread2 działają push() i pop() odpowiednio. Tylko jeden z nich znajdzie się w sekcji krytycznej na raz.

  • Jeśli thread2 posiada blokadę, albo nigdy nie czeka, bo kolejka nie jest pusta (tak „utraty” a zawiadomić jest nieszkodliwy), albo siedzi tam czeka na powiadomienie, (które nie zostaną utracone) .

  • Jeśli wątek1 ma blokadę, wstawi element do kolejki; jeśli wątek2 czekał, zostanie poprawnie zgłoszony; jeśli wątek2 wciąż czekał na muteks, nigdy nie będzie czekać, ponieważ w kolejce znajduje się co najmniej jeden element, więc utrata powiadomienia jest nieszkodliwa.

W ten sposób powiadomienie jest tracone tylko wtedy, gdy nie było potrzebne w pierwszej kolejności.

Teraz, jeśli masz inne zastosowanie dla zmiennych warunkowych, gdzie "utrata" powiadomienia ma jakiekolwiek konsekwencje, wydaje mi się, że masz albo wyścig, albo używasz niewłaściwego narzędzia.

+0

Czy możesz obejrzeć moją edycję? dzięki. – MRB

+0

Jeśli chcesz zadać nowe pytanie, opublikuj nowe pytanie, nie edytuj swojego starego pytania, aby zmienić/dodać niepowiązane rzeczy. Ponadto, nie piszę bcRead lBadly mIndented BAND LIntally pObfuscated bcCode. – DanielKO

Powiązane problemy