互斥量是系統內核對象,誰擁有就誰執行。它與臨界區工作很類似。不同處在於:1、互斥量可以跨進程邊界同步線程。2、可以給互斥量取個名字,通過引用互斥量的名字來使用一個已知的互斥量對象。
使用互斥量之類的對象需要反復調用系統內核,期間需要進行進程上下文轉換和控制級別轉換,大概需要耗費400到600個時間周期。
又是圖書館的比喻,現在是搞一個鎖,把鑰匙(互斥量句柄)交給管理員(操作系統),每一個人(線程)想要借書的時候,都要向管理員拿鑰匙。當有人在使用的時候,另一人必須等待,等到鑰匙有空的時候(互斥量進入信號狀態),才能拿到鑰匙(擁有了句柄)辦理借書業務(此時互斥量進入非信號狀態直到辦完業務)。
使用互斥量的步驟:
1、聲明一個全局的互斥量句柄變量(var hMutex: THandle;);
2、創建互斥量:CreateMutex(
lpMutexAttributes: PSecurityAttributes;
bInitialOwner: BOOL;
lpName: PWideChar ): THandle;
(lpMutexAttributes參數:指向TSecurityAttributes的指針,安全屬性,一般用缺省安全屬性nil;
bInitialOwer參數:表示創建的互斥量線程是否是互斥量的屬主,如果該參數為False互斥量就沒屬主,一般來講應設為False,否則如果設為True的話,要當主線程結束其他線程才成為它的屬主才能運行;
lpName參數:是互斥量的名字,若打算取名的話,則傳入nil。)
3、用等待函數控制線程進入同步代碼塊:WaitForSingleObject(
hHandle:THandel;
dwMilliseconds:DWORD):DWORD;
(hHandel參數:是對象的句柄,不同對象信號狀態不同,對於互斥量而言當沒有線程占有時,互斥量就時入信號狀態;
dwMilliseconds參數:可以是一個時間段,可以是0表示僅檢查對象狀態后立即返回,可以是INFINITE值表示函數一直等待直到對象進入信號狀態;
返回值常量如下:WAIT_ABANDONED指定的對象是互斥量對象,擁有這個互斥量對象的線程在沒有釋放互斥量之前就已經終止,稱作廢棄互斥量,此時該互斥量歸調用線程所擁有,並把這個互斥量設為非信號狀態;WAIT_OBJECT_0指定對象的進入信號狀態;WAIT_TIMEOUT等待時間已過,對象狀態依然是無信號狀態)
4、執行線程運行代碼。
5、線程運行完后釋放互斥量的擁有權:ReleaseMutex(hMutex: THandle);
6、最后關閉互斥量:CloseHandle(hMutex: THandle);
同樣的例子,使用互斥量:
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls;
- type
- TForm2 = class(TForm)
- ListBox1: TListBox;
- Button1: TButton;
- procedure Button1Click(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- var
- Form2: TForm2;
- hMutex:THandle;
- implementation
- uses MyThread;
- {$R *.dfm}
- procedure TForm2.Button1Click(Sender: TObject);
- begin
- TMyThread.Create(False);
- TMyThread.Create(False);
- TMyThread.Create(False);
- end;
- procedure TForm2.FormCreate(Sender: TObject);
- begin
- hMutex:=CreateMutex(nil,false,'MyThreadDemo');
- end;
- procedure TForm2.FormDestroy(Sender: TObject);
- begin
- CloseHandle(hMutex);
- end;
- end.unit MyThread;
- interface
- uses
- Classes,StdCtrls,SysUtils,Windows;
- type
- TMyThread = class(TThread)
- private
- { Private declarations }
- str:String;
- procedure AddList;
- protected
- procedure Execute; override;
- end;
- implementation
- uses Unit2;
- { TMyThread }
- procedure TMyThread.AddList;
- begin
- Form2.ListBox1.Items.Add(str);
- end;
- procedure TMyThread.Execute;
- var
- i:Integer;
- begin
- { Place thread code here }
- FreeOnTerminate:=True;
- if WaitForSingleObject(hMutex,INFINITE)=WAIT_OBJECT_0 then
- begin
- try
- for i := 0 to 99 do
- begin
- if not Terminated then
- begin
- str:=Format('線程ID:%.4d,第%.2d個循環。',[GetCurrentThreadId,i]);
- Synchronize(AddList);
- end;
- end;
- finally
- ReleaseMutex(hMutex);
- end;
- end;
- end;
- end.
運行結果與前文相似,這里借用前文的圖(除了線程ID不同)
