On Jul 29, 2008, at 4:57 AM, Vladimir Pozdyaev wrote:
Howard Hinnant:
On Jul 28, 2008, at 6:49 AM, Vladimir Pozdyaev wrote:
Looking at, e.g.,
http://www.opengroup.org/onlinepubs/009695399/functions/pthread_cond_init.ht...
reveals that "It shall be safe to destroy an initialized condition variable upon which no threads are currently blocked." Am I right in understanding that the wait-destroy sequence should be quite safe this way (provided no one else waits)?
I believe your code as shown is subject to "spurious wakeup". If the wait ends (spuriously) before the notify_all() completes, or is even initiated, then the notify happens on a destructed cv. POSIX says that in this case the pthread_cond_broadcast will return EINVAL.
I believe I should apologise for this distraction. I am aware of possibility of spurious wakeups; they are one reason for the claim that the original code is not an example of good practice. The point is, spurious wakeups have nothing to do with the problem at hand, so I just opted for a more concise code sample.
The sentence you refer to means that the thread doing the notifying can safely destroy the cv even if the waiting thread has not yet returned from the wait (as long as that thread or any other do not try to initiate a new wait after the final signal/broadcast). Note though
This is a somewhat narrower interpretation, since the original sentence does not consider roles of threads (notifying or waiting). Is it a matter of bad wording on the part of the latter? Because I don't see in what way does my code contradict the condition "no threads are currently blocked" (on a cv). AFAICT, after the only cv.wait has finished...
that it is not safe to destruct the mutex which is being waited on, until the waiting thread wakes from the wait (locking the mutex) and then unlocks that mutex.
... and the only (scoped) lock on a mutex released, no threads are blocked on them, so it shouldn't be problematic to destroy both mutex and cv, should it?
(The problem doesn't seem to reproduce with a trunk version of the lib, so the point may well be moot anyway, but still I'm wondering...)
For the moment consider that all mutex and cv operations are atomic. They can not be interrupted (as if they were a single machine instruction). In this model your code is still not safe. You have a race: Does the cv get destructed before cv.notify_all() is called? The answer is that we don't know. If it does, you have undefined behavior. You would be referencing a member of a destructed object. Can you construct code that will reliably test your question? Your current code does not. If your question can not be tested, then the answer becomes irrelevant. To be clear, your original code would be just as "correct" if you commented out the cv.wait(l) in ~C(). Because of spurious wakeups, this call to wait does not *reliably* have any effect whatsoever. -Howard