January 2007
M T W T F S S
« Dec   Feb »
1234567
891011121314
15161718192021
22232425262728
293031  

Chris Donnan : Programming - Brooklyn Style

software, trading, family, fun

Locking and signaling

I have had several chats with software developers lately that were working hard to use locking to perform some task. In each of these conversations, the simple solution was to use signaling, not just locking semantics.

I have found over time that for some reason, software developers all know about lock semantics. This has many varieties, lock keyword in C# (really a Monitor usage), Monitor.Enter, java synchronized, java ReentrantLock, etc, Mutexes, etc. The point of locking semantics is to mark a bit of code as a ‘critical section’ or a section that requires exclusive access to it - 1 thread or process at a time. There are varieties like Read/ Write locks, etc - but it is all essentially the same for lock semantics.

Lock/ synchronized/ critical section behavior is certainly mandatory, however as they say “when all you have is a hammer, everything is a nail”. Locks are not THE ONLY tool you can use to accomplish more complex multi-threaded goals. Signaling is another KEY set of abstractions that exists in java, .net, pthreads, Win32, etc, etc.

In java, all objects have signal and wait, in .net there are several choices, Monitor.Wait/ Monitor.Pulse, AutoResetEvents, ManualResetEvents, etc. Signals are used to communicate between concurrently executing threads.

I often ask developers in interviews to implement a blocking queue. Basically - what I am looking for is to see if they understand signaling. A simple blocking queue allows 1 thread to enqueue freely, and another thread to dequeue as long as there is at least 1 object to dequeue. If there is NO object to deque - the caller should be blocked. Signalling is the correct solution. People try to do Thread.Sleep, or say something like while ( _queue.Count > o) - both of which generally are not the best solution. There are plenty of more elaborate solutions - but here is a simple example.

class BlockingQueue< T >
{
Queue< T > _queue = new Queue< T >();
object _queueSync = new object();

void Enqueue(T value)
{
lock(_queueSync)
{
_queue.Enqueue(value);
Monitor.Pulse(_queueSync);
}
}

T Dequeue()
{
lock(_queueSync)
{
if( _queue.Count < 1)
Monitor.Wiat(_queueSync);

return _queue.Dequeue()
}
}
}

(PS Blog software killed some >’s and <'s in the code -sorry I am too lazy to fiddle)

This is a very simple signaling example. WaitHandles, Auto/Manual Reset Events are related - and allow you to accomplish all the more complex inter-thread communication. There are still other ‘higher level’ abstractions like Condition Variables, Latches and the like. I encourage EVERY developer to absolutely get more intimate with these constructs. It is SO common to have poor threading code because developers do not know the tools provided, and when to apply them. It is MUCH easier to use a countdown latch construct than to jury rig some interweaving of thread joins or locks etc. The 1.5 JDK now incorporates some of the very best constructs - read into them -use them if you are writing java. .Net also has lots of excellent constructs. Get beyond locks and your code will get simpler and it will actually work !

-Chris

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • del.icio.us
  • digg
  • blinkbits
  • BlinkList
  • blogmarks
  • YahooMyWeb
  • connotea
  • De.lirio.us
  • Fark
  • Furl
  • Reddit
  • description
  • Shadows
  • Smarking
  • Spurl
  • TailRank
  • Wists

Comment on this post below

You must be logged in to post a comment.


You can leave a response, or trackback from your own site.