26 Temmuz 2024 Yazarı yhackup 0

Kim korkar Semaphore’dan

Merhabalar,

Senkronizasyon (synchronization) mekanizmalarından biri olan Semaphore’la ilgili bir örnek yapacağız.

Basit bir dille anlatmak gerekirse, Birden fazla işin (process) aynı anda çalıştığında birbirleri için risk oluşturabileceği anlarda (critical sections) ,  diğer işleri bekletmesini sağlatan bir mekanizma türüdür.

Bir hayali örnek ile ilerleyelim açıkçası ben alaylı olduğum için mantığını biraz geç anladım Tuğrul bey sağ olsun yardımcı oldu, Biz şimdi Semaphore’u bir berber dükkanı olarak hayal edelim.

Bir berber dükkanı açmak istedik ve parayı bulduk berber dükkanı açtık. OpenSemaphore(SEMAPHORE_ALL_ACCESS, false,PWideChar(‘yhackup’));

function OpenSemaphore(dwDesiredAccess: DWORD; bInheritHandle: BOOL; lpName: LPCWSTR): THandle; stdcall;
{$EXTERNALSYM OpenSemaphore}

 

Semaphore berber dükkanımız küçük olduğu için şimdilik 5 koltuk koyabildik, ve Sabah dükkanı açtık 5 koltuğun 5’ide boş. CreateSemaphore(nil, 5, 5, PWideChar(‘yhackup’)

function CreateSemaphore(lpSemaphoreAttributes: PSecurityAttributes;
  lInitialCount, lMaximumCount: Longint; lpName: LPCWSTR): THandle; stdcall;

 

5 koltuğu olan bir berberde bir koltuğa 2 kişi oturamaz veya bir berber 2 kişiyi traş edemez , aynı ipte iki cambaz oynamaz.

Her bir berber(TThread) bir kişi alarak traşını yapar, yeni gelen saçı sakalı birbirine karışmış bireyler sırasını bekler. WaitForSingleObject(MySemaphore, INFINITE);

function WaitForSingleObject(hHandle: THandle; dwMilliseconds: DWORD): DWORD; stdcall;

 

Her bir berberin bir kişiyi traş etmesi 5 saniye sürer. Sleep(5000); 

procedure Sleep(milliseconds: Cardinal); stdcall;

 

Traş olan kişi parasını öder koltuktan kalkar ReleaseSemaphore(MySemaphore, 1, nil); ve 1 kişilik yer açılır. yeni Müşteri gelir.

function ReleaseSemaphore(hSemaphore: THandle; lReleaseCount: Longint;
  lpPreviousCount: Pointer): BOOL; stdcall;

 

Kodlara geçmeden sistemin nasıl çalıştığını gösteren bir video izleyelim.

 

unit USemaphore;
 
interface
 
uses
 Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
 System.Classes, Vcl.Graphics,
 Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 
type
 TSemaForm = class(TForm)
   GroupBox1: TGroupBox;
   GroupBox2: TGroupBox;
   GroupBox3: TGroupBox;
 
   iceridekilist: TListBox;
   bekleyenlist: TListBox;
   cikanlist: TListBox;
 
   CreateButton: TButton;
   procedure FormCreate(Sender: TObject);
   procedure AddList(Text: String; Wait: Integer);
   procedure NewSemaphore(Text: String);
   procedure CreateButtonClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;
 
var
 SemaForm: TSemaForm;
 MySemaphore: THandle;
 a: integer = 0;
 
implementation
 
{$R *.dfm}
 
procedure TSemaForm.AddList(Text: String; Wait: Integer);
begin
 case Wait of
   0: // Bekliyor listesine ekle
     begin
       TThread.Queue(nil,
         procedure
         begin
           bekleyenlist.Items.Add(Text);
         end);
     end;
   1: // İçeride listesine ekle
     begin
       TThread.Queue(nil,
         procedure
         var
           i: integer;
         begin
           for I := 0 to bekleyenlist.Count - 1 do
           begin
             if bekleyenlist.Items[i] = Text then
             begin
               bekleyenlist.Items.Delete(i);
               iceridekilist.Items.Add(Text);
               Break;
             end;
           end;
         end);
     end;
   2: // Bitti listesine ekle
     begin
       TThread.Queue(nil,
         procedure
         var
           i: integer;
         begin
           for I := 0 to iceridekilist.Count - 1 do
           begin
             if iceridekilist.Items[i] = Text then
             begin
               iceridekilist.Items.Delete(i);
               cikanlist.Items.Add(Text);
               Break;
             end;
           end;
         end);
     end;
 end;
end;
 
procedure TSemaForm.CreateButtonClick(Sender: TObject);
begin
 NewSemaphore('Semaphore-' + IntToStr(a));
 Inc(a);
end;
 
procedure TSemaForm.FormCreate(Sender: TObject);
begin
 MySemaphore := OpenSemaphore(SEMAPHORE_ALL_ACCESS, false,PWideChar('yhackup'));
 if MySemaphore = 0 then
 begin                           // 5 kişilik yer var, 5 yer de boş
   MySemaphore := CreateSemaphore(nil, 5, 5, PWideChar('yhackup'));
 end;
end;
 
procedure TSemaForm.NewSemaphore(Text: String);
var
  str: string;
begin
  str := Text;
  TThread.CreateAnonymousThread(
    procedure
    begin
      // Dükkana Yeni müşteri geliyor,
      // Eğer 5 koltukta dolu ise MySemaphore berberinde,
      // kişi INFINITE kadar bekliyor.
      // ReleaseSemaphore ile bir kişilik yer açıltığında.
      AddList(str, 0);
      WaitForSingleObject(MySemaphore, INFINITE);

      // Boş koltuğa geçebiliyor.


      // kişi Burada Traş Olmakta
      AddList(str, 1);
      Sleep(5000);
      // kişi Burada Traş Olmakta


      // Traş burada bitiyor, Berberin çıkış kapısından müşteri çıkıyor..
      ReleaseSemaphore(MySemaphore, 1, nil);
      AddList(str, 2);
    end).Start;
end;
 
end.

 

Kalın Sağlıcakla…