What happens if I wake a condition variable when nobody is waiting for it? Is the wake saved for the next thread that waits?

Date:September 25, 2017 / year-entry #214
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20170925-00/?p=97075
Comments:    6
Summary:It shouldn't matter.

Suppose you call Wake­Xxx­Condition­Variable to wake a CONDITION_VARIABLE, but nobody is waiting on the condition variable. What happens? In particular, is the wake saved for the next thread that waits, so the next call to Sleep­Condition­Variable­Xxx returns immediately instead of waiting?

The answer is, "It shouldn't matter."

The intended use pattern for a condition variable is to do the following:

  1. Enter a lock.
  2. Check a condition.
  3. If the condition is false, then call Sleep­Condition­Variable­Xxx and then go to step 2.
  4. Perform an operation.
  5. Release the lock.

And the code that establishes the condition (or at least changes the condition so it might be true for at least one waiter) calls Wake­Xxx­Condition­Variable.

If you follow this pattern, then it doesn't matter whether a call to Wake­Xxx­Condition­Variable is remembered when there are no waiting threads. According to the intended use pattern, a thread is expected to check the condition first, and only if the condition is false should the thread call Sleep­Condition­Variable­Xxx. Whether the wake is remember or not is irrelevant because the waiting thread never actually waits!

In other words, if you are counting on an unnecessary wake being saved and waking up a future sleep, then that means that you went to sleep before checking the condition. (Because if you had checked the condition, you would have avoided the sleep.) You're holding it wrong.

Conversely, if you didn't expect the unnecessary wake to be remembered, but you got one anyway, well, that's also permitted because condition variables are explicitly documented as subject to spurious wakes. Again, if you follow the intended use pattern, spurious wakes aren't a problem (aside from performance) because the recommended pattern is to re-check the condition after the sleep wakes. If the wake were spurious, the check would fail, and you would go back to sleep.

In summary, if you wake a condition variable when nobody is waiting for it, it is unspecified whether the wake is saved for the next thread that waits, and that's okay, because if you follow the intended use pattern, it doesn't matter.


Comments (6)
  1. Mike says:

    > spurious wakes aren’t a problem (aside from performance)

    I’m not sure why you dismiss performance so casually… If the CV wakes a thread (spurious or not), the thread by definition is holding a mutex which means other threads may not be able to make progress (on top of a potentially needless context switch). That by itself might be a genuine problem if many of the wakeups are spurious.

    You shouldn’t say it absolutely doesn’t matter — you can only say it _usually_ doesn’t matter.

    As an aside, C++11’s std::condition_variable specifies a total “happens before” ordering on CV wakeups and wait()s to address this issue.

    1. I’m saying that spurious wakeups aren’t a problem from a correctness point of view. They impact performance but not correctness.

    2. Clockwork-Muse says:

      …. except, unless I’m missing something, it doesn’t actually address these issues so much as abstract the loop away. Even then, spurious wakeups can happen for unrelated reasons, so handling the condition is essentially some form of standard “tax”

    3. I’ve just had a look through the last C++11 draft (n3337), and I can’t find the language you’re referring to. 30.5 requires an unspecified total order for the parts of the CV operation, and 30.5.1 says that spurious wake-ups are allowed.

      There’s a variant on wait that takes a predicate, and is documented to be equivalent to while(!predicate) wait();, but possibly using library optimizations to reduce spurious wake-ups. However, it’s legitimate to have spurious wake-ups and tests of the predicate.

      1. Mike says:

        > I’ve just had a look through the last C++11 draft (n3337), and I can’t find the language you’re referring to. 30.5 requires an unspecified total order for the parts of the CV operation, and 30.5.1 says that spurious wake-ups are allowed.

        In the C++17 draft (n4660), section 33.5:

        The implementation shall behave as if all executions of notify_one, notify_all, and each part of the wait,
        wait_for, and wait_until executions are executed in a single unspecified total order consistent with the
        “happens before” order.

        That combined with the definition of notify_all() (Unblocks all threads that are blocked waiting for *this), unambiguously addresses the “is the wake saved for the next thread that waits” question in the first paragraph.

    4. Zan Lynx' says:

      The spurious wake is hardly ever a problem for performance although of course you need to profile to be sure.
      It is usually caused by a broadcast wake sent to multiple waiters. By the time the “spurious” wake happens, the other threads have consumed all available work events. And so the wasted wake mutexes are burned on threads doing no work but don’t interrupt the other threads, because they’re busy working.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index