Sleep(1) in spinlock in lwm_win32.hpp

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, 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. ~ Sleep(1); ~ } ~ } ~ ~scoped_lock() ~ { ~ 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 big deal. 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 iD8DBQFArHA7lp/lhnWsM8QRAganAJ9tW7F8axtjSeTqp9ZDmXKuNb2a3QCgl1ZO 4CMavVQnkH7DNtZmd4Fitgw= =te8D -----END PGP SIGNATURE-----
participants (1)
-
Aaron W. LaFramboise