Wednesday, December 31, 2008

How to use a critical section to prevent inconsistencies in threads

 
Suppose you are creating a class TProblemSolver that solves a problem by putting several threads to work. For argument's sake, we'll assume these threads are implemented in a class TProblemThread, derived from TThread. This is not necessary, however. Let's say that these threads, when they're done, increment a variable in TProblemSolver that shows how many threads are done.

TProblemSolver = class
private
  CriticalSection: TCriticalSection;
  FThreadsDone: integer;
public
  procedure Solve;
  procedure IncThreadsDone;
end;

So all threads call IncThreadsDone at some point. The problem is that while IncThreadsDone is running, another thread may decide to call it as well. This will lead to bugs.

procedure TProblemThread.Execute;
begin
  ...
  ProblemSolver.IncThreadsDone;
end;

The solution is to include a critical section, which blocks threads from entering a piece of code when another thread already has.

The implementation of IncThreadsDone then becomes the following :

procedure TProblemSolver.IncThreadsDone;
begin
  CriticalSection.Enter;
  try
    // safe now
    inc(FThreadsDone);
  finally
    CriticalSection.Leave;
  end;
end;

Now it is certain that whatever happens inside IncThreadsDone, is safe and will occur as it has to: one thread at a time.

Using critical sections can lead to performance penalties, so only use them around blocks of code that need it. This is code that accesses data shared by more than one thread.

Note that the critical section being used has to be the same for all threads that access the same data. This is the reason I included the calls to Enter and Leave in IncThreadsDone.


Mulai chatting dengan teman di Yahoo! Pingbox baru sekarang!!
Membuat tempat chat pribadi di blog Anda sekarang sangatlah mudah

0 Comments: