Search code examples
c++multithreadingspurious-wakeup

Does a spurious wake up unblock all waiting threads, even the unrelated ones?


I'm still new to multi-threading in C++ and I'm currently trying to wrap my head around "spurious wake-ups" and what's causing them. I've done some digging on condition variables, kernel signals, futex, etc., and found several culprits on why and how "spurious wake-ups" occur, but there is still something that I can't find the answer to...

Question: Will a spurious wake-up unblock all waiting/blocked threads, even the ones waiting for a completely unrelated notification? Or are there separate waiting queues for the blocked threads and therefore the threads waiting for another notification are protected?

Example: Let's say that we have 249 Spartans waiting to attack the Persians. They wait() for their leader, Leonidas (the 250th) to notify_all() when to attack. Now, on the other side of the camp there are 49 injured Spartans who are waiting for the doctor (the 50th) to notify_one() so that he could treat each one. Would a spurious wake-up unblock all waiting Spartans, including the injured ones, or would it only affect the ones waiting for battle? Are there two separate queues for the waiting threads, or just one for all?

Apologies if the example is misleading... I didn't know how else to explain it.


Solution

  • Causes for spurious wakeups are specific to each operating system, and so are the properties of such wakeups. In Linux, for example, a wakeup happens when a signal is delivered to a blocked thread. After executing the signal handler the thread does not block again and instead receives a special error code (usually EINTR) from the system call that it was blocked on. Since signal handling does not involve other threads, they do not get woken up.

    Note that spurious wakeup does not depend on the synchronization primitive you're blocking on or the number of threads blocked on that primitive. It may also happen with non-synchronization blocking system calls like read or write. In general, you have to assume that any blocking system call may return prematurely for whatever reason, unless it is guaranteed not to by a specification like POSIX (and even then, there may be bugs and OS specifics that deviate from the specification).

    Some attribute superfluous notifications to spurious wakeups because dealing with both is usually the same. They are not the same, though. Unlike spurious wakeups, superfluous notifications are actually caused by another thread and are the result of a notify operation on the condition variable or futex. It's just the condition that you check upon the wakeup could turn to false before the unblocked thread manages to check it.