Why 'wait with predicate' solves the 'lost wakeup' for condition variable?

后端 未结 1 1207
一向
一向 2020-12-20 08:40

I am trying to understand the difference between spurious vs lost wakeup in case of a condition variable. Following is small piece code I tried. I understand that \'consumer

相关标签:
1条回答
  • 2020-12-20 08:44

    It is the atomic "unlock and wait" operation that prevents lost wakeups. A lost wakeup happens this way:

    1. We acquire the lock that protects the data.
    2. We check to see whether we need to wait and we see that we do.
    3. We need to release the lock because otherwise no other thread can access the data.
    4. We wait for a wakeup.

    You can see the risk of a lost wakeup here. Between steps 3 and 4, another thread could acquire the lock and send a wakeup. We have released the lock, so another thread can do this, but we aren't waiting yet, so we wouldn't get the signal.

    So long as step 2 is done under the protection of the lock and steps 3 and 4 are atomic, there is no risk of a lost wakeup. A wakeup cannot be sent until the data is modified which cannot be done until another thread acquires the lock. Since 3 and 4 are atomic, any thread that sees the lock as unlocked will necessarily also see us waiting.

    This atomic "unlock and wait" is the primary purpose of condition variables and the reason they must always be associated with a mutex and a predicate.

    In code above, consumer is not waiting for first few notifications because it is sleeping. Is it not missing notify in this case? Is this case not similar to race condition between #3 and #4?

    Nope. Can't happen.

    Either the consumer that is not waiting holds the lock or it doesn't. If the consumer that is not waiting holds the lock, it can't miss anything. The predicate cannot change when it holds the lock.

    If the consumer is not holding the lock, then it doesn't matter what it misses. When it checks to see whether it should lock in step 2, if it missed anything, it will necessarily see it in step 2 and it will see that it does not need to wait, so it will not wait for the wakeup that it missed.

    So if the predicate is such that the thread does not need to wait, the thread will not wait because it checks the predicate. There is no opportunity for a missed wakeup prior to step 1.

    The only time an actual wakeup is needed is if a thread goes to sleep. The atomic unlock and sleep ensures that a thread can only decide to go to sleep while it holds the lock and while the thing it needs to wait for has not yet happened.

    0 讨论(0)
提交回复
热议问题