A nice touch to the Python Lock class interface is the ability to specify whether or not an acquisition attempt should block, waiting until the lock is acquired, or just fall through if it is not available. The latter functionality is also known as “test and set”.
In C# the blocking part can be done with a
AutoResetEvent, while the testandset can be achieved with an actual variable test and set (rather, a CAS:
Interlocked.CompareExchange). However, there is no readily available mutex object that provides both functionalities at the same time, as Python’s Lock does.
So, I rolled my own. A custom (thread-safe) C# lock that supports test and set as well as blocking acquisition. Bonus feature: non-modifying blocking and events for locking and unlocking (useful for waiting until a certain event took place).
As always, be careful when using this. Note that the
WaitWhile(Un)Locked functions, specifically, can get you in trouble. There is no way of knowing when a call to that function has actually started registering the corresponding event. Thread scheduling could cause it to still be hanging at the function entry without actually having done anything. Meanwhile, another thread that you wanted to wait for may be firing away and doing its job, unbeknownst to your monitoring thread. Avoid this, for example by ensuring that a thread would not flip the state twice (e.g. one locker thread, and one unlocker thread, waiting for eachother).
Better yet, use queues and similar thread safe data channels to pass around data. This lock is intended for simple, boolean synchronization.
The code is available as a gist on https://gist.github.com/2133167.