[fpc-pascal] Counting semaphore for free pascal

kapibara kapibara.pas at aol.com
Tue Jul 28 20:07:52 CEST 2015


Hi there,

A counting, or general, semaphore limits simultaneous access to a 
resource according to the number of permits you specify. On the other 
hand, a binary semaphore like a critical section limits the access to 
"one at a time".

FPC doesn't seem to have a general semaphore? I recently attempted to 
implement one, here is the code, plus a working Lazarus demo attached. 
It blocks on an event instead of a critical section. However, I didnt 
manage to have it block by just calling Wait, because then the code 
blocked without leaving the PermitLock and that meant deadlock for all 
threads. So thats why you see the "if Semaphore.Wait(aEvent) then 
RTLEventWaitFor(aEvent)" instead of just Semaphore.Wait(aEvent). It 
works just fine, but if anyone knows how to implement this by just 
calling Wait(aEvent), please tell. If you want to block on a critical 
section instead of an event, do that. Perhaps the result could be 
TFPSemaphore and go with FPC.

unit kbsemaphore;

{$mode objfpc}{$H+}

interface

uses
   Classes, SysUtils, syncobjs, contnrs;

type

   { TKBSemaphore }

   TKBSemaphore = class
   private
     FPermits: Cardinal;
     FPermitLock: TCriticalSection;
     FBlockQueue: TQueue;
     function GetWaitCount: Cardinal;
   public
     function Wait(var AEvent: PRTLEvent): Boolean;
     procedure Post;
     constructor Create(MaxPermits: Cardinal);
     destructor Destroy; override;
     property WaitCount: Cardinal read GetWaitCount;  //Approximate 
precision!
     property Permits: Cardinal read FPermits;
   end;


implementation

{ TKBSemaphore }

function TKBSemaphore.GetWaitCount: Cardinal;
begin
   FPermitLock.Enter;
   Result:= FBlockQueue.Count;
   FPermitLock.Leave;
end;

function TKBSemaphore.Wait(var AEvent: PRTLEvent): Boolean;
begin
   FPermitLock.Enter;
   if (FPermits > 0) then
   begin
     Dec(FPermits);
     Result:= False;
   end
   else
   begin
     AEvent:= RTLEventCreate;
     FBlockQueue.Push(AEvent);
     Result:= True;
   end;
   FPermitLock.Leave;
end;

procedure TKBSemaphore.Post;
begin
   FPermitLock.Enter;
   if FBlockQueue.Count > 0 then
   begin
     RTLeventSetEvent(PRTLEvent(FBlockQueue.Peek));
     RTLeventdestroy(PRTLEvent(FBlockQueue.Pop));
   end
   else
     Inc(FPermits);

   FPermitLock.Leave;
end;

constructor TKBSemaphore.Create(MaxPermits: Cardinal);
begin
   FPermits:= MaxPermits;
   FPermitLock:= TCriticalSection.Create;
   FBlockQueue:= TQueue.Create;
end;

destructor TKBSemaphore.Destroy;
begin
   FPermitLock.Free;
   FBlockQueue.Free;
   inherited Destroy;
end;

end.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: KBSemaphoreDemo.zip
Type: application/x-zip-compressed
Size: 5157 bytes
Desc: not available
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20150728/127bb395/attachment.bin>


More information about the fpc-pascal mailing list