While it’s been in the product for a few versions now, I’ve come across very little example code for TMonitor, despite its implementation having been heavily blogged about by its author (Allen Bauer) while he actually was writing it. In this post and its sequel, I’ll be looking to help rectify that, if only in a very small way.

Naturally, your first question may well be to ask what on earth is TMonitor. One answer is that it is a Delphi implementation of the Monitor class in .NET, having a very similar interface to the latter and essentially the same functionality. Of course, .NET didn’t invent the concept of a ‘monitor’, and you can read more about it on Wikipedia. In short, a monitor is the combination of a critical section and a ‘condition variable’. If you’re like me, the second part of this sounds very jargon-y, with the first leading to the thought ‘what’s the point?’ – after all, Delphi has a TCriticalSection class, or if you prefer, direct access to the Windows critical section API. In contrast, in .NET, Monitor is the critical section class, which – naturally enough – makes it quite essential over there (the fact the critical section aspect is also given some syntactical sugar in C# with the lock keyword can’t not help either). So, what is the point back in Delphi-land?

In essence, what TMonitor adds over a regular critical section object is a signalling capability — a very primitive signalling capability admitedly, but a signalling capability nonetheless. To give a flavour, here’s a more or less direct Delphi translation of a C# example of Joe Albahari’s (source):

program SimpleWaitPulse; {$APPTYPE CONSOLE} uses Classes; var Go: Boolean; Thread: TThread; begin Thread := TThread.CreateAnonymousThread( procedure begin TMonitor.Enter(Thread); try while not Go do TMonitor.Wait(Thread, INFINITE); WriteLn('Woken!!!'); finally TMonitor.Exit(Thread); end; end); Thread.Start; ReadLn; TMonitor.Enter(Thread); try Go := True; TMonitor.Pulse(Thread); finally TMonitor.Exit(Thread); end; ReadLn; end.

This starts a new thread that, on taking the lock, immediately releases it to wait on the Go variable becoming True. The latter happens when the user presses ENTER, upon which the main thread takes the lock, sets Go to True, ‘pulses’ the change in state, before finally releasing the lock.

Even though this is a very simple example – so simple in fact it fails to show up WriteLn’s lack of thread safety (ahem)! – there’s a few things to note from it:

As always with locking primitives, use of try/finally is very much necessary.

The sort of state waited on is entirely up to the discretion of the code that uses TMonitor.

The Wait and Pulse calls are made within an Enter/Exit pair. The call to Wait therefore releases the lock, allowing another thread to get in and call Pulse. The Pulse call itself then wakes the thread at the top of the Wait queue. In the present example there’s only one waiter, but if there were more than one and you wished to wake all of them, you should call PulseAll rather than Pulse several times.

Regarding the Wait call again, observe how it is made in the context of a while loop. In this case that isn’t strictly necessary, since there’s only going to be one waiter waiting on a single boolean condition. Matters would be different, though, whenever there is more than one consumer — between being released and acting on the pulsed state, that state may have been changed by another newly-released thread.

With this knowledge, we can use TMonitor to implement a simple threaded queue class, wrapping the standard TQueue. As for the actual implementation, you’ll have to wait to my next post though.