多線程編程(4) – 多線程同步之 Mutex (互斥對象)

來源:互聯網
上載者:User

原理分析:
互斥對象是系統核心對象, 各線程都可以擁有它, 誰擁有誰就能執行;
執行完畢, 用 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 將直接建立一個新的互斥對象; 下個例子將會有名字. }
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;
Mutex 作為系統核心對象是可以跨進程的(臨界區就不行), 我們可以利用互斥對象禁止程式重複啟動.

工作思路:
先用 OpenMutex 嘗試開啟一個自訂名稱的 Mutex 對象, 如果開啟失敗說明之前沒有這個對象存在;
如果之前沒有這個對象, 馬上用 CreateMutex 建立一個, 此時的程式應該是第一次啟動;
再重複啟動時, 那個 OpenMutex 就有結果了, 然後強制退出.
最後在程式結束時用 CloseHandle 釋放 Mutex 對象.

function OpenMutex(  dwDesiredAccess: DWORD; {開啟許可權}  bInheritHandle: BOOL;   {能否被當前程式建立的進程繼承}  pName: PWideChar        {Mutex 對象的名稱}): THandle; stdcall;      {成功返回 Mutex 的控制代碼; 失敗返回 0}

注意, 這裡的 CreateMutex 函數應該有個名了, 因為 OpenMutex 要用到;
另外, CreateMutex 的第二個參數已經不重要了(也就是 True 和 False 都行), 因為這裡是用其名稱來判斷的.

程式可以這樣寫:

unit Unit1;interfaceuses  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,  Dialogs;type  TForm1 = class(TForm)    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);  end;var  Form1: TForm1;implementation{$R *.dfm}var  hMutex: THandle;const  NameMutex = 'MyMutex';procedure TForm1.FormCreate(Sender: TObject);begin  if OpenMutex(MUTEX_ALL_ACCESS, False, NameMutex) <> 0 then  begin    ShowMessage('該程式已啟動');    Application.Terminate;  end;  hMutex := CreateMutex(nil, False, NameMutex);end;procedure TForm1.FormDestroy(Sender: TObject);begin  CloseHandle(hMutex);end;end.

這一般都是寫在 dpr 主程式裡, 省得讓後啟動的程式執行些無用的代碼:

program Project1;uses  Forms, Windows,  Unit1 in 'Unit1.pas' {Form1};{$R *.res}var  hMutex: THandle;const  NameMutex = 'MyMutex';begin  {主線程入口}  if OpenMutex(MUTEX_ALL_ACCESS, False, NameMutex) <> 0 then  begin    MessageBox(0, '該程式已啟動', '提示', MB_OK);    Application.Terminate;  end;  hMutex := CreateMutex(nil, False, NameMutex);  Application.Initialize;  Application.MainFormOnTaskbar := True;  Application.CreateForm(TForm1, Form1);  Application.Run;  CloseHandle(hMutex);  {主線程出口}end.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.