Semaphore (信號量/信號燈) 是支援**多資源並發存取**的核心同步物件,類比「銀行多櫃台服務」:計數器表示可用資源數,線程等待獲取信號 (WaitForSingleObject),用畢釋放 (ReleaseSemaphore)。本文完整解析參數、API 版與 TSemaphore 封裝類雙實現。
function CreateSemaphore(
lpSemaphoreAttributes: PSecurityAttributes; // 安全屬性,通常 nil
lInitialCount: Longint; // 初始可用信號數 (當前資源數)
lMaximumCount: Longint; // 最大信號數 (資源總上限)
lpName: PWideChar // 具名支援跨進程
): THandle; stdcall;
WaitForSingleObject(hSem, INFINITE) 申請信號:
ReleaseSemaphore(hSem, 1, nil) 釋放:
MaximumCount = 1 時退化為 Mutex。unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm)
Button1: TButton; Edit1: TEdit;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Edit1KeyPress(Sender: TObject; var Key: Char);
end;
var Form1: TForm1;
implementation {$R *.dfm}
var f: Integer; hSemaphore: THandle;
function MyThreadFun(p: Pointer): DWORD; stdcall;
var i, y: Integer;
begin
Inc(f); y := 20 * f;
if WaitForSingleObject(hSemaphore, INFINITE) = WAIT_OBJECT_0 then
begin
for i := 0 to 1000 do
begin
Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock;
Sleep(1);
end;
ReleaseSemaphore(hSemaphore, 1, nil); // 歸還信號
end;
Result := 0;
end;
procedure TForm1.Button1Click(Sender: TObject);
var ThreadID: DWORD;
begin
CloseHandle(hSemaphore);
hSemaphore := CreateSemaphore(nil, StrToInt(Edit1.Text), 5, nil); // 最大 5,初始由 Edit1 決定
Repaint; f := 0;
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
end;
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if not CharInSet(Key, ['1'..'5']) then Key := #0; // 限制 1-5
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := '1';
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
CloseHandle(hSemaphore);
end;
end.
uses SyncObjs;
var MySemaphore: TSemaphore;
procedure TForm1.Button1Click(Sender: TObject);
var ThreadID: DWORD;
begin
if Assigned(MySemaphore) then MySemaphore.Free;
MySemaphore := TSemaphore.Create(nil, StrToInt(Edit1.Text), 5, ''); // 初始、最大、名稱
Repaint; f := 0;
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
end;
function MyThreadFun(p: Pointer): DWORD; stdcall;
var i, y: Integer;
begin
Inc(f); y := 20 * f;
if MySemaphore.WaitFor(INFINITE) = wrSignaled then
begin
for i := 0 to 1000 do
begin
Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock;
Sleep(1);
end;
MySemaphore.Release; // 釋放信號 (預設 +1)
end;
Result := 0;
end;

object Form1: TForm1
object Button1: TButton OnClick = Button1Click
object Edit1: TEdit OnKeyPress = Edit1KeyPress Text = '1'
end
| 特性 | Semaphore | Mutex | CriticalSection |
|---|---|---|---|
| 並發資源數 | 可配置 (1..N) | 固定 1 | 固定 1 |
| 跨進程 | ✅ 具名 | ✅ 具名 | ❌ |
| 核心物件開銷 | 有 | 有 | 無 (用戶態) |
| 釋放權限 | 任何線程可 Release | 僅擁有者可 Release | 任何線程可 Leave |
| 遞歸鎖定 | 不支援 | ✅ 支援 | ✅ 支援 |
ReleaseSemaphore(hSem, ReleaseCount, lpPreviousCount):
ReleaseCount:通常 1,可一次釋放多個信號。lpPreviousCount:非 nil 時接收釋放**前**的計數值 (調試用)。TSemaphore.Release(Count: Integer = 1):封裝版支援批量釋放。Semaphore 以其「可配置並發度、跨進程、釋放無擁有權限制」特性,成為資源池、限流器、生產消費者等經典並發模式的原生最佳實現。