Draft: 1st
Date: 22 Jan. 08
Author: Niall Munro
Title: GS: Assistant Data Analyst
Address: Generation Scotland Office
Room D38
Medical Genetics (OPD2)
2nd Floor, Out Patients Department
Western General Hospital
Crewe Road South
Edinburgh
EH4 2XU
Email: niall.munro@ed.ac.uk
DELPHI HOWTO:
THREADS
CONTENTS
Introduction 1
Declaring Your Thread 1
Staying alive 2
Synchronisation 3
Conclusion 3
Full Example 4
Useful Links 5
Example 1: Thread Skeleton Code Example 1
Example 2: Thread Declaration 1
Example 3: Keep alive loop 2
Example 4: Example code for thread signalling 2
Example 5: Synchronising global variables 3
Example 6: Full Example Code 4
Delphi Howto: Threads
1 | P a g e
INTRODUCTION
Threads are units of code which run independently of the main process essentially allowing multiple instances
to be executed in parallel. This technique is useful in allowing time consuming processes to run in their own
instance whilst allowing the main part of your code to continue instead of waiting for the process to complete.
unit ExampleThread;
interface
uses
Classes;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
implementation
procedure TMyThread.Execute;
begin
{ Place thread code here }
end;
end.
Example 1: Thread skeleton code example
DECLARING YOUR THREAD
Declaring a thread in the main section of your code is the same as initiating any other object with a constructor,
a thread takes one argument which is a Boolean value that defines whether or not to start the thread once
initialized.
MyThread1 := TMyThread(false)// start thread immediately
MyThread2 := TMyThread(true) // do not start thread immediately
MyThread2.Resume; // Start/Resume thread execution
MyThread2.Terminate; // Stop Thread
Example 2: Thread declaration
Delphi Howto: Threads
2 | P a g e
STAYING ALIVE
The Execute procedure is where your code will be triggered once the thread has been started. You can add
further procedures and variables to your thread as you would to any other Delphi unit. Once the code of your
thread has been executed it will exit like any other function, generally developers create threads which they
wish to remain in an active state either suspended or waiting for instructions to process.
In order to keep the thread alive we must introduce a loop into the main Execute procedure
while not Terminated do
begin
{ Insert your code here }
end;
Example 3: Keep alive loop
If this loop were allowed to run it would quickly consume all of your processors resources so we must either
introduce a Spinning or Blocking technique. Spinning is a wasteful technique which puts the process to sleep for
a specified time before looping again e.g. sleep(100); The second technique uses events to control the state
of your thread where it waits for a TEvent Object to signal it to proceed, use like so:
// Initialisation of global TEvent object
MyEvent := TEvent.Create(nil, false, false, 'WorkerThreads');
MyEvent.ResetEvent;
...
// Place the following inside the thread loop
If <Some Condition> = true then
begin
{ Insert your code here }
end
else
MyEvent.WaitFor(INFINITE);
Example 4: Example code for thread signalling
The MyEvent.WaitFor(INFINITE) declaration stops the thread from looping and until the global
MyEvent objects SetEvent procedure is called, the thread will wait at that point until signalled. Multiple threads
can rely on a single event object, if the SetEvent method is called whilst multiple threads are in the waiting state
it would trigger all threads to proceed once again. It is good practice to have a conditional statement within the
main loop that checks whether a condition is true and if not put that the thread into a waiting state as shown
above, the condition can be something like whether a work queue has anything to process.
Delphi Howto: Threads
3 | P a g e
SYNCHRONISATION
Threads share the same memory space as the main part of your code thus allowing access to variables that are
declared in the global scope. However this is not without its own issues, this is why most languages include
multiple means to lock variables whilst a process does its thing and then releases it, and this is called
synchronisation.
Methods of synchronisation include:
 Critical Sections – The simplest form of synchronisation it locks variables from being read or written to
by other processes. Critical Selections encapsulate the variables being worked on using the Acquire and
Release methods, the class is called TCriticalSection. Use this method if you will be making
as many writes as reads.
 TMultiReadExclusiveWriteSynchronizer – This synchronisation class is slightly different in that it allows
multiple reads of global variables but allows only one write lock at a time. This class is best suited to
applications where threads do more reading than writing as this method provides better performance
than Critical Selections. All access to shared variables should be encapsulated within BeginRead and
EndRead or BeginWrite and EndWrite otherwise the application will eventually run into thread conflicts.
// Initialise critical selection
CS := TCriticalSelection.Create;
...
// Thread Code
try
CS.Enter;
if WorkQueue.Count > 0 then
begin
// Process Instruction
WorkQueue.Delete(0);
end;
finally
CS.Leave;
end;
Example 5: Synchronising global variables
CONCLUSION
On the following page is an example with all of the ideas above combined into a single thread unit. Note that
the thread uses the GlobalVars unit which is supposed to hold the WorkQueue and MyEvent objects so that
the code may interact with it.
Delphi Howto: Threads
4 | P a g e
FULL EXAMPLE
unit ExampleThread;
interface
uses
Classes, GlobalVars;
type
TMyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
procedure ProcessQueue;
end;
implementation
procedure TMyThread.Execute;
begin
while not Terminated do
begin
If <Some Condition> = true then
begin
try
CS.Enter;
if WorkQueue.Count > 0 then
begin
// Process Instruction
ProcessQueue(WorkQueue.ValueFromIndex[0]);
WorkQueue.Delete(0);
end;
finally
CS.Leave;
end;
end
else
MyEvent.WaitFor(INFINITE);
end;
end;
end.
procedure TMyThread.ProcessQueue;
begin
...
end;
Example 6: Full example code
Delphi Howto: Threads
5 | P a g e
USEFUL LINKS
Delphi threading by example - http://dn.codegear.com/article/22411
Threading in C# - http://www.albahari.com/threading/
Threads, thread objects and its use - http://www.ibrtses.com/delphi/threads.html

Delphi - Howto Threads

  • 1.
    Draft: 1st Date: 22Jan. 08 Author: Niall Munro Title: GS: Assistant Data Analyst Address: Generation Scotland Office Room D38 Medical Genetics (OPD2) 2nd Floor, Out Patients Department Western General Hospital Crewe Road South Edinburgh EH4 2XU Email: niall.munro@ed.ac.uk DELPHI HOWTO: THREADS
  • 2.
    CONTENTS Introduction 1 Declaring YourThread 1 Staying alive 2 Synchronisation 3 Conclusion 3 Full Example 4 Useful Links 5 Example 1: Thread Skeleton Code Example 1 Example 2: Thread Declaration 1 Example 3: Keep alive loop 2 Example 4: Example code for thread signalling 2 Example 5: Synchronising global variables 3 Example 6: Full Example Code 4
  • 3.
    Delphi Howto: Threads 1| P a g e INTRODUCTION Threads are units of code which run independently of the main process essentially allowing multiple instances to be executed in parallel. This technique is useful in allowing time consuming processes to run in their own instance whilst allowing the main part of your code to continue instead of waiting for the process to complete. unit ExampleThread; interface uses Classes; type TMyThread = class(TThread) private { Private declarations } protected procedure Execute; override; end; implementation procedure TMyThread.Execute; begin { Place thread code here } end; end. Example 1: Thread skeleton code example DECLARING YOUR THREAD Declaring a thread in the main section of your code is the same as initiating any other object with a constructor, a thread takes one argument which is a Boolean value that defines whether or not to start the thread once initialized. MyThread1 := TMyThread(false)// start thread immediately MyThread2 := TMyThread(true) // do not start thread immediately MyThread2.Resume; // Start/Resume thread execution MyThread2.Terminate; // Stop Thread Example 2: Thread declaration
  • 4.
    Delphi Howto: Threads 2| P a g e STAYING ALIVE The Execute procedure is where your code will be triggered once the thread has been started. You can add further procedures and variables to your thread as you would to any other Delphi unit. Once the code of your thread has been executed it will exit like any other function, generally developers create threads which they wish to remain in an active state either suspended or waiting for instructions to process. In order to keep the thread alive we must introduce a loop into the main Execute procedure while not Terminated do begin { Insert your code here } end; Example 3: Keep alive loop If this loop were allowed to run it would quickly consume all of your processors resources so we must either introduce a Spinning or Blocking technique. Spinning is a wasteful technique which puts the process to sleep for a specified time before looping again e.g. sleep(100); The second technique uses events to control the state of your thread where it waits for a TEvent Object to signal it to proceed, use like so: // Initialisation of global TEvent object MyEvent := TEvent.Create(nil, false, false, 'WorkerThreads'); MyEvent.ResetEvent; ... // Place the following inside the thread loop If <Some Condition> = true then begin { Insert your code here } end else MyEvent.WaitFor(INFINITE); Example 4: Example code for thread signalling The MyEvent.WaitFor(INFINITE) declaration stops the thread from looping and until the global MyEvent objects SetEvent procedure is called, the thread will wait at that point until signalled. Multiple threads can rely on a single event object, if the SetEvent method is called whilst multiple threads are in the waiting state it would trigger all threads to proceed once again. It is good practice to have a conditional statement within the main loop that checks whether a condition is true and if not put that the thread into a waiting state as shown above, the condition can be something like whether a work queue has anything to process.
  • 5.
    Delphi Howto: Threads 3| P a g e SYNCHRONISATION Threads share the same memory space as the main part of your code thus allowing access to variables that are declared in the global scope. However this is not without its own issues, this is why most languages include multiple means to lock variables whilst a process does its thing and then releases it, and this is called synchronisation. Methods of synchronisation include:  Critical Sections – The simplest form of synchronisation it locks variables from being read or written to by other processes. Critical Selections encapsulate the variables being worked on using the Acquire and Release methods, the class is called TCriticalSection. Use this method if you will be making as many writes as reads.  TMultiReadExclusiveWriteSynchronizer – This synchronisation class is slightly different in that it allows multiple reads of global variables but allows only one write lock at a time. This class is best suited to applications where threads do more reading than writing as this method provides better performance than Critical Selections. All access to shared variables should be encapsulated within BeginRead and EndRead or BeginWrite and EndWrite otherwise the application will eventually run into thread conflicts. // Initialise critical selection CS := TCriticalSelection.Create; ... // Thread Code try CS.Enter; if WorkQueue.Count > 0 then begin // Process Instruction WorkQueue.Delete(0); end; finally CS.Leave; end; Example 5: Synchronising global variables CONCLUSION On the following page is an example with all of the ideas above combined into a single thread unit. Note that the thread uses the GlobalVars unit which is supposed to hold the WorkQueue and MyEvent objects so that the code may interact with it.
  • 6.
    Delphi Howto: Threads 4| P a g e FULL EXAMPLE unit ExampleThread; interface uses Classes, GlobalVars; type TMyThread = class(TThread) private { Private declarations } protected procedure Execute; override; procedure ProcessQueue; end; implementation procedure TMyThread.Execute; begin while not Terminated do begin If <Some Condition> = true then begin try CS.Enter; if WorkQueue.Count > 0 then begin // Process Instruction ProcessQueue(WorkQueue.ValueFromIndex[0]); WorkQueue.Delete(0); end; finally CS.Leave; end; end else MyEvent.WaitFor(INFINITE); end; end; end. procedure TMyThread.ProcessQueue; begin ... end; Example 6: Full example code
  • 7.
    Delphi Howto: Threads 5| P a g e USEFUL LINKS Delphi threading by example - http://dn.codegear.com/article/22411 Threading in C# - http://www.albahari.com/threading/ Threads, thread objects and its use - http://www.ibrtses.com/delphi/threads.html