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…