We have already seen in Chapter 6, and in particular in the section "Thread Synchronization with the VCL" that the TThread has been extended to take advantage of anonymous methods. The extensions take the form of new overloaded versions of the Synchronize and Queue methods, so existing Delphi code should work smoothly.
Another new feature of Delphi 2009 is the presence of the TMonitor record105, a data structure defined in the System unit that you can use to provide synchronous access to any object. This monitor support, which resembles the corresponding class of the .NET framework, let's you define a thread lock tied to a specific object. Rather than having a global synchronization semaphore, you can set one for each control to which you want to allow concurrent access, letting a thread at a time use it.
In other words, the TMonitor record grants a lock for an object to a single thread. However, multiple threads can work on different objects at the same time. To acquire a lock on an object you can call the Enter or the TryEnter methods, while you release the lock (generally in a finally block) using the Exit method. The TMonitor record in Delphi support locks and also conditional variables, though the Wait, Pulse, and PulseAll methods, a complex topic I decided not to cover with an example, but focus only on a simpler scenario.
The ListMonitor example has a form with three list boxes and multiple threads accessing those lists in a random way. Each thread operation is fictitiously slow (thanks to a call to Sleep), but other threads interested in using the list box will have to wait.
The thread class used by the program has the core code, which writes a starting and a stopping message to the list, waiting in between. This code code is protected with a TMonitor connected to the given list object, to avoid any other thread using the list before the first thread is finished:
105 The TMonitor record is defined in the System unit. This is important to know, as it is very easy to have conflicts with the TMonitor class, defined in the Forms unit. If your unit refers to Forms, in fact, there is no way you can list System after it, as System is invariably the first unit referenced by any other unit. In other words, you'll often have to write System .TMonitor to refer to the record. Even if it was named after its .NET counterpart, I find this choice quite confusing.
224 - Chapter 7: More Language and RTL Changes type
TAddToListThread = class(TThread) protected procedure Execute; override; end;
procedure TAddToListThread.Execute; var aList: TListBox; I: Integer; begi n while not Terminated do begi n aList := Application.MainForm.FindComponent ( 'ListBox' + IntToStr (GetTickCount mod 3 + 1)) as TListBox; System.TMonitor.Enter (aList); try aList.Items.Add(lntToStr (GetCurrentThreadlD) +
' starting: ' + TimeToStr (Now)); // wait loop, omitted aList.Items.Add(lntToStr (GetCurrentThreadlD) + ' stopping: ' + TimeToStr (Now)); fi nal ly
System.TMonitor.Exit (aList); end; end; end;
As I mentioned earlier, the test program for this thread class has three list boxes, added to a list as the program starts, plus a list of threads (notice I'm using generic collections in both cases):
procedure TFormListMonitor.FormCreate(Sender: TObject); begi n fThreads := TObjectList<TThread>.Create; fListBoxes := TList<TListBox>.Create; fListBoxes.Add (ListBox1); fListBoxes.Add (ListBox2); fListBoxes.Add (ListBox3); end;
The threads are added to the list, three at time, when a buttons is pressed:
Sender: TObject); var
I: Integer; begi n for I := 1 to 3 do fThreads.Add (TAddToListThread.Create (False));
The other button is used to check the lock on the list objects, using the TryEnter call and bailing out immediately when the object is available:
Sender: TObject); var aListBox: TListBox; begi n for aListBox in fListBoxes do begi n if System.TMonitor.TryEnter(aListBox) then try aListBox.Items.Add( 'Available'); fi nal ly
Was this article helpful?
What you need to know about… Project Management Made Easy! Project management consists of more than just a large building project and can encompass small projects as well. No matter what the size of your project, you need to have some sort of project management. How you manage your project has everything to do with its outcome.