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

Delphi 多線程程式設計 (13):Event 事件對象 - 最靈活的同步原語完整指南

     編輯:Delphi

Event (事件對象) 是 Windows 核心同步物件中**最靈活**的一種,擁有「手動/自動重置」與「初始狀態」雙重控制,支援隨時 SetEvent (啟動)、ResetEvent (暫停)、PulseEvent (單次脈衝) 動態控制線程執行流。本文完整解析 Event 參數、API 封裝類 TEvent 及實戰範例。

CreateEvent 參數詳解

function CreateEvent(
  lpEventAttributes: PSecurityAttributes;  // 安全屬性,通常 nil
  bManualReset: BOOL;                      // 核心參數 1:重置模式
  bInitialState: BOOL;                     // 核心參數 2:初始狀態
  lpName: PWideChar                        // 具名支援跨進程
): THandle; stdcall;

核心控制 API

  • SetEvent(hEvent):設為有信號 → 釋放等待線程 (手動重置釋放所有,自動重置釋放一個)。
  • ResetEvent(hEvent):設為無信號 → 後續等待線程阻塞。
  • PulseEvent(hEvent):原子操作:設為有信號 → 釋放等待線程 → 立即設為無信號。相當於「單次脈衝」,僅喚醒當前正在等待的線程。

API 版完整範例:動態啟動/暫停/脈衝控制

unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm)
  Button1, Button2, Button3, Button4, Button5: TButton;
  procedure FormCreate(Sender: TObject);
  procedure FormDestroy(Sender: TObject);
  procedure Button1Click(Sender: TObject);  // CreateEvent
  procedure Button2Click(Sender: TObject);  // CreateThread
  procedure Button3Click(Sender: TObject);  // ResetEvent
  procedure Button4Click(Sender: TObject);  // SetEvent
  procedure Button5Click(Sender: TObject);  // PulseEvent
end;
var Form1: TForm1;
implementation {$R *.dfm}

var f: Integer; hEvent: THandle;

function MyThreadFun(p: Pointer): DWORD; stdcall;
var i, y: Integer;
begin
  Inc(f); y := 20 * f;
  for i := 0 to 200000 do
    if WaitForSingleObject(hEvent, INFINITE) = WAIT_OBJECT_0 then
    begin
      Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock;
    end;
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Repaint; f := 0;
  CloseHandle(hEvent);
  hEvent := CreateEvent(nil, True, True, nil);  // 手動重置 + 初始有信號
end;

procedure TForm1.Button2Click(Sender: TObject);
var ThreadID: DWORD;
begin
  CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ResetEvent(hEvent);  // 暫停
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  SetEvent(hEvent);    // 啟動
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  PulseEvent(hEvent);  // 單次脈衝
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Button1.Caption := '建立 Event';
  Button2.Caption := '建立線程';
  Button3.Caption := 'ResetEvent (暫停)';
  Button4.Caption := 'SetEvent (啟動)';
  Button5.Caption := 'PulseEvent (單次)';
end;

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

TEvent 封裝類版本 (SyncObjs 單元)

uses SyncObjs;

var MyEvent: TEvent;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Repaint; f := 0;
  if Assigned(MyEvent) then MyEvent.Free;
  MyEvent := TEvent.Create(nil, True, True, '');  // 手動重置、初始有信號、無名
end;

procedure TForm1.Button2Click(Sender: TObject);
var ThreadID: DWORD;
begin
  CreateThread(nil, 0, @MyThreadFun, nil, 0, ThreadID);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  MyEvent.ResetEvent;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  MyEvent.SetEvent;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  ShowMessage('TEvent 無 PulseEvent 等效方法');  // 可嘗試 PulseEvent(MyEvent.Handle) 但不保證
end;

function MyThreadFun(p: Pointer): DWORD; stdcall;
var i, y: Integer;
begin
  Inc(f); y := 20 * f;
  for i := 0 to 200000 do
    if MyEvent.WaitFor(INFINITE) = wrSignaled then
    begin
      Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock;
    end;
  Result := 0;
end;

執行效果展示

按鈕動態控制線程啟動/暫停/單次脈衝

DFM 定義

object Form1: TForm1
  object Button1: TButton OnClick = Button1Click Caption = '建立 Event'
  object Button2: TButton OnClick = Button2Click Caption = '建立線程'
  object Button3: TButton OnClick = Button3Click Caption = 'ResetEvent'
  object Button4: TButton OnClick = Button4Click Caption = 'SetEvent'
  object Button5: TButton OnClick = Button5Click Caption = 'PulseEvent'
end

Event 核心優勢總結

參數FalseTrue
bManualReset**自動重置**:喚醒單一線程後自動歸零 (無信號)**手動重置**:保持有信號直到手動 ResetEvent,喚醒**所有**等待線程
bInitialState**無信號 (非觸發)**:建立後線程等待會阻塞**有信號 (觸發)**:建立後線程等待立即通過
特性EventMutexSemaphoreCriticalSection
動態啟動/暫停✅ Set/Reset❌❌❌
單次脈衝✅ PulseEvent❌❌❌
喚醒所有/單一✅ 手動/自動重置單一計數控制單一
跨進程✅ 具名✅ 具名✅ 具名❌
效能核心物件開銷核心物件核心物件**用戶態 極快**

實務應用模式

  1. 工作線程池控制:手動重置 Event 作為「暫停/繼續」開關,主線程隨時 SetEvent/ResetEvent。
  2. 單次任務觸發:自動重置 Event + PulseEvent 精確喚醒一個空閒線程。
  3. 階段同步屏障:多線程各自完成階段 1 → SetEvent 通知主線程 → 主線程 ResetEvent → 釋放進入階段 2。
  4. 優雅關閉:全域「退出 Event」,主線程 SetEvent,所有工作線程檢測到退出迴圈。

TEvent 缺失補充

TEvent 缺乏 PulseEvent 封裝,需直接呼叫 API PulseEvent(MyEvent.Handle),但官方文檔不保證此用法穩定,建議關鍵路徑直接用 API。

Event 以其「隨時可控、單次脈衝、全喚醒/單喚醒雙模式」成為複雜線程協調編排的首選核心同步物件。

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