互斥對象是系統內核對象, 各線程都可以擁有它, 誰擁有誰就能執行;
執行完畢, 用 ReleaseMutex 函數釋放擁有權, 以讓其他等待的線程使用.
其他線程可用 WaitForSingleObject 函數排隊等候(等候也可以理解爲排隊申請).
使用過程:
var hMutex: THandle; {應該先聲明一個全局的互斥句柄} CreateMutex {建立一個互斥對象} WaitForSingleObject {用等待函數排隊等候} ReleaseMutex {釋放擁有權} CloseHandle {最後釋放互斥對象}
ReleaseMutex、CloseHandle 的參數都是 CreateMutex 返回的句柄, 關鍵是 CreateMutex 函數:
function CreateMutex( lpMutexAttributes: PSecurityAttributes; bInitialOwner: BOOL; {是否讓創建者(此例中是主線程)擁有該互斥對象} lpName: PWideChar {可以給此互斥對象取個名字, 如果不要名字可賦值爲 nil} ): THandle; { 1、第一個參數前面說過. 2、第二個參數在這裏一定要是 False, 如果讓主線程擁有互斥, 從理論上講, 得等程序退出後其他線程纔有機會; 取值 False 時, 第一個執行的線程將會最先擁有互斥對象, 一旦擁有其他線程就得先等等. 3、第三個參數, 如果給個名字, 函數將從系統中尋找是否有重名的互斥對象, 如果有則返回同名對象的存在的句柄; 如果賦值爲 nil 將直接創建一個新的互斥對象; 下個例子將會有名字. }
本例效果圖:
代碼文件:
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; {互斥對象的句柄} 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 hMutex := CreateMutex(nil, False, nil); end; procedure TForm1.FormDestroy(Sender: TObject); begin CloseHandle(hMutex); end; end.
窗體文件:
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 140 ClientWidth = 192 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object Button1: TButton Left = 109 Top = 107 Width = 75 Height = 25 Caption = 'Button1' TabOrder = 0 OnClick = Button1Click end end
SyncObjs 單元下有封裝好的 TMutex 類, 好像不如 Api 快, 內部機制也稍有區別, 但使用方法差不多:
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} uses SyncObjs; var f: Integer; MyMutex: TMutex; function MyThreadFun(p: Pointer): DWORD; stdcall; var i,y: Integer; begin Inc(f); y := 20 * f; for i := 0 to 50000 do begin if MyMutex.WaitFor(INFINITE) = wrSignaled then begin Form1.Canvas.Lock; Form1.Canvas.TextOut(20, y, IntToStr(i)); Form1.Canvas.Unlock; MyMutex.Release; 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 MyMutex := TMutex.Create(False); end; procedure TForm1.FormDestroy(Sender: TObject); begin MyMutex.Free; end; end.
原文:http://www.cnblogs.com/del/archive/2009/02/13/1390295.html
謝謝萬一老師的講解