From: Aaron W. LaFramboise (aaronrabiddog51_at_[hidden])
Date: 2004-05-20 03:51:48
-----BEGIN PGP SIGNED MESSAGE-----
I was doing some research on implementing fast mutexes in Windows for
GCC, and in the course of doing various sorts of benchmarks, I came
across something very disturbing. I've noticed a lot of discussion of
the Windows spinlocks before, but I don't think this came up.
By default on Windows when using lightweight mutexes, Boost acquires
and releases a spinlock using this code:
~ explicit scoped_lock(lightweight_mutex & m): m_(m)
~ while( InterlockedExchange(&m_.l_, 1) )
~ // Note: changed to Sleep(1) from Sleep(0).
~ // According to MSDN, Sleep(0) will never yield
~ // to a lower-priority thread, whereas Sleep(1)
~ // will. Performance seems not to be affected.
~ InterlockedExchange(&m_.l_, 0);
~ // Note: adding a yield here will make
~ // the spinlock more fair and will increase the overall
~ // performance of some applications substantially in
~ // high contention situations, but will penalize the
~ // low contention / single thread case up to 5x
First, I verified the claim that Sleep(1) yields to low-priority
threads, and this is, in fact, true.
However, when benchmarking, I noticed that it in fact sleeps slightly
more than 10ms by default on Windows XP! Other platforms seem to have
similar results. This is a very long time.
Using timeBeginPeriod(), it is possible to lower this to 1ms, but in
no case when Sleep has a positive parameter will Windows sleep for a
period shorter than this. Unfortunately, timeBeginPeriod() is part of
of mmsystem and on every compiler I am familiar with, requires linking
against an additional import library, winmm. This may or may not be a
In any case, the present code seems very suboptimal, and in some
situations, it could be ridiculously slow, compared to the standard
Windows synchronization primatives it is working so hard to avoid. I
would suggest that if there were another Boost release that included
this code, the situation involving this spinlock would need to be
documented somewhere obvious.
I think, though, that we could trivially improve this code without too
much effort and without compromising its goals. In particular, the
loop could spin for a while using Sleep(0), which is orders of
magnitude faster, before falling back to Sleep(1)--presumably because
a thread of lower priority holds the lock. This should eliminate 90%
of the practical problem, but definitely is not a perminant solution.
Aaron W. LaFramboise
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
-----END PGP SIGNATURE-----
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk