Question

I want to have two procedures which can call each other, or be called from whatever threads are running, but only have one running at a time. How can I do this? Will this work correctly?

var
  cs: TCriticalSection;

procedure a;
begin
  cs.Acquire;
  try
    // Execute single threaded here. 
  finally
    cs.Release;
  end;
end;

procedure b;
begin
  cs.Acquire;
  try
    // Execute single threaded here. Maybe with calls to procedure a.
  finally
    cs.Release;
  end;
end;
Was it helpful?

Solution

Yes, that will work. Procedure A can call B and vice versa within the same thread and while Thread A is using procedure A or B, Thread B has to wait when it wants to use those procedures.

See the MSDN documentation about Critical Sections: http://msdn.microsoft.com/en-us/library/ms682530%28VS.85%29.aspx

Critical sections can be nested, but for every call to Acquire you must have a call to Release. Because you have your Release call in a try .. finally clause you ensure that this happens, so your code is fine.

OTHER TIPS

While it is possible on Windows to acquire a critical section multiple times, it is not possible on all platforms, some of them will block on the attempt to re-acquire a synchronization object.

There is not really a need to allow for "nesting" here. If you design your classes properly, in a way that the public interface acquires and releases the critical section, and the implementation methods don't, and if you make sure that implementation methods never call interface methods, then you don't need that particular feature.

See also the Stack Overflow question "Recursive Lock (Mutex) vs Non-Recursive Lock (Mutex)" for some details on the bad sides of recursive mutex / critical section acquisition.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top