10.3 Critical sections

When programming threads, it is sometimes necessary to avoid concurrent access to certain resources, or to avoid having a certain routine executed by two threads. This can be done using a Critical Section. The FPC heap manager uses critical sections when multithreading is enabled.

The TRTLCriticalSection type is an Opaque type; it depends on the OS on which the code is executed. It should be initialized before it is first used, and should be disposed of when it is no longer necessary.

To protect a piece of code, a call to EnterCriticalSection should be made: When this call returns, it is guaranteed that the current thread is the only thread executing the subsequent code. The call may have suspended the current thread for an indefinite time to ensure this.

When the protected code is finished, LeaveCriticalSection must be called: this will enable other threads to start executing the protected code. To minimize waiting time for the threads, it is important to keep the protected block as small as possible.

The definition of these calls is as follows:

procedure InitCriticalSection(var cs: TRTLCriticalSection);  
procedure DoneCriticalSection(var cs: TRTLCriticalSection);  
procedure EnterCriticalSection(var cs: TRTLCriticalSection);  
procedure LeaveCriticalSection(var cs: TRTLCriticalSection);

The meaning of these calls is again almost obvious:

InitCriticalSection
Initializes a critical section. This call must be made before either EnterCrititicalSection or LeaveCriticalSection is used.
DoneCriticalSection
Frees the resources associated with a critical section. After this call neither EnterCrititicalSection nor LeaveCriticalSection may be used.
EnterCriticalSection
When this call returns, the calling thread is the only thread running the code between the EnterCriticalSection call and the following LeaveCriticalsection call.
LeaveCriticalSection
Signals that the protected code can be executed by other threads.

Note that the LeaveCriticalsection call must be executed. Failing to do so will prevent all other threads from executing the code in the critical section. It is therefore good practice to enclose the critical section in a Try..finally block. Typically, the code will look as follows:

Var  
  MyCS : TRTLCriticalSection;  
 
Procedure CriticalProc;  
 
begin  
  EnterCriticalSection(MyCS);  
  Try  
    // Protected Code  
  Finally  
    LeaveCriticalSection(MyCS);  
  end;  
end;  
 
Procedure ThreadProcedure;  
 
begin  
  // Code executed in threads...  
 CriticalProc;  
  // More Code executed in threads...  
end;  
 
begin  
  InitCriticalSection(MyCS);  
  // Code to start threads.  
  DoneCriticalSection(MyCS);  
end.