Boost logo

Boost :

From: Roland Schwarz (roland.schwarz_at_[hidden])
Date: 2006-12-07 14:26:21


Yuval Ronen wrote:
> ... And it is only obvious that all reads and writes to the
> shared-among-threads predicate should be locked. Shouldn't it?

Of course, the predicate access needs to be locked. But there is no
requirement for the signaling part, since this does not access the
predicate.

> ... also greatly improve CV
> performance on Windows).

Do you mean: Requirement to hold the lock while signaling will improve
speed ?

If so I might tell you, that the intent of not requiring to hold the
mutex while signaling is expected to improve speed. Butenhof
(Programming with Posix Threads) says:

   "Although you must have the associated mutex locked to wait on a
condition variable, you can signal (or broadcast) a condition variable
with the associated mutex unlocked if that is more convenient. The
advantage of doing so is that, on many systems, this may be more
efficient. When a waiting thread awakens, it must first lock the mutex.
If the thread awakens while a signaling thread holds the mutex, then the
awakened thread must immediately block on the mutex - you've gone
through two context switches to get back where you started. (There is an
optimization, which I've called wait morphing, that moves a thread
directly from the condition variable wait queue to the mutex wait queue
in this case, without a context switch, when the mutex is locked. This
optimization can produce a substantial performance benefit for many
applications.)
Weighing on the other side is the fact that, if the mutex is not locked,
any thread (not only the one being awakened) can lock the mutex prior to
the thread being awakened. This race is one source of intercepted
wakeups. A lower-priority thread, for example, might lock the mutex
while another thread was about to awaken a very high-priority thread,
delaying scheduling of the high-priority thread. If the mutex remains
locked while signaling, this cannot happen - the high-priority waiter
will be placed before the lower-priority waiter onr the mutex and will
be scheduled first."

I might be wrong, but AFAIK "wait morphing" generally cannot be done in
a user-space library, it needs to intimately interact with the scheduler.

> Providing an interface that will ensure for
> notifying, locking the *same* mutex as when waiting, ...
...
> What I'm suggesting is that the condition constructor would accept a
> mutex reference and store it. The Lock& argument to the wait() method
> will be removed, as there's already a reference to the mutex. It might
> also be useful to templatize the condition class for Mutex type:

What would this be of help for? Changing a predicate needs locking the
mutex, not signaling it. If you mean that the signal function internally
first should lock the mutex, signal and then unlock it, this would make
things even worse (And is quite different from the case Butenhof
addresses in the above citation, since this will be of no help in the
priority case.)

Also putting the mutex into the condition ctor would make construction
unnecessary complicated. E.g. how would you do in the following (quite
common) case:

class foo {

mutex m;
condition c;
};

Btw.: I highly recommend reading Butenhofs book, it not only covers
pthreads, but will help getting a better general understanding of
threading too.

Regards,
Roland


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk