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.