首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

多線程程式設計(10):使用 Mutex 實現線程同步

     編輯:Delphi

Mutex(互斥對象)原理與運作機制

Mutex(Mutual Exclusion Object,互斥對象)是 Windows 核心提供的一種同步原語,屬於核心對象。它的核心特性是同一時間只允許一個線程擁有它。擁有 Mutex 的線程可以進入受保護的程式碼區段(Critical Section),其他試圖獲取同一 Mutex 的線程將被迫排隊等待,直到擁有者釋放它為止。

核心 API 流程

  1. CreateMutex:建立或開啟一個具名/無名的 Mutex 物件,返回核心物件句柄(THandle)。
  2. WaitForSingleObject:線程呼叫此函數請求擁有權。若 Mutex 空閒,立即獲得並繼續執行;若已被佔用,線程進入等待狀態(可設定超時或無限等待 INFINITE)。
  3. ReleaseMutex:擁有者執行完畢後呼叫,釋放擁有權,喚醒下一個等待線程。
  4. CloseHandle:程式結束前關閉句柄,釋放核心資源。

CreateMutex 關鍵參數解析

function CreateMutex(
  lpMutexAttributes: PSecurityAttributes; // 安全屬性,通常為 nil
  bInitialOwner: BOOL;                    // 建立者是否立即擁有,多線程下建議 False
  lpName: PWideChar                       // 物件名稱,nil 為無名;同名則跨進程共享
): THandle; stdcall;
  • bInitialOwner = False:讓第一個呼叫 WaitForSingleObject 的線程搶到擁有權,避免主線程長期佔用導致其他線程飢餓。
  • lpName:指定名稱可實現跨進程同步;若為 nil,則僅限進程內部線程間同步。

完整範例:五條線程輪流在畫布輸出數字

下列程式碼示範如何使用 Mutex 保護 Canvas 繪圖操作,確保多線程不會同時存取 Canvas 導致畫面錯亂。

unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  end;
var Form1: TForm1;
implementation {$R *.dfm}
var
  f: Integer;           // 協調各線程輸出垂直位置
  hMutex: THandle;      // 全域 Mutex 句柄

function MyThreadFun(p: Pointer): DWORD; stdcall;
var i, y: Integer;
begin
  Inc(f);
  y := 20 * f;          // 每條線程佔一行
  for i := 0 to 50000 do
  begin
    // 請求擁有權,無限等待
    if WaitForSingleObject(hMutex, INFINITE) = WAIT_OBJECT_0 then
    begin
      Form1.Canvas.Lock;
      Form1.Canvas.TextOut(20, y, IntToStr(i));
      Form1.Canvas.Unlock;
      Sleep(0);         // 讓出時間片,緩解 Canvas 壓力
      ReleaseMutex(hMutex);
    end;
  end;
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var ThreadID: DWORD;
begin
  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.FormCreate(Sender: TObject);
begin
  // 建立無名 Mutex,初始擁有者為 False
  hMutex := CreateMutex(nil, False, nil);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  CloseHandle(hMutex);
end;
end.

使用 SyncObjs.TMutex 封裝類

Delphi 的 SyncObjs 單元提供 TMutex 類,用法更符合物件導向風格,內部同樣呼叫核心 API,效能略低但碼碼更清晰:

uses SyncObjs;
var MyMutex: TMutex;
// 建立
MyMutex := TMutex.Create(False);
// 等待
if MyMutex.WaitFor(INFINITE) = wrSignaled then
begin
  // 受保護區域
  MyMutex.Release;
end;
// 釋放
MyMutex.Free;

效果展示

Mutex 同步執行畫面

五條線程依序在各自行輸出 0~50000,畫面整齊無重疊,證明 Mutex 成功序列化了 Canvas 存取。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved