C# 中的 Mutex(互斥體)基礎用法

阿遇而已發表於2024-10-10

C# 中的 Mutex(互斥體)基礎用法

在多執行緒程式設計中,互斥體(Mutex) 是一種用於同步執行緒訪問共享資源的機制。它確保同一時間只有一個執行緒可以訪問特定的資源,防止資料競爭和資源衝突。在 C# 中,System.Threading.Mutex 類提供了實現互斥體的功能。

目錄

  1. 什麼是 Mutex?
  2. Mutex 與其他同步機制的比較
  3. Mutex 的基本用法
  4. 命名 Mutex
  5. Mutex 的跨程序同步
  6. 使用 Mutex 的注意事項
  7. 示例程式碼
  8. 總結

1. 什麼是 Mutex?

Mutex(Mutual Exclusion) 是一種同步原語,用於在多個執行緒或程序之間控制對共享資源的訪問。Mutex 可以在同一程序內的多個執行緒之間同步,也可以在不同程序之間同步。

關鍵特點:

  • 互斥性:同一時間只能有一個執行緒持有 Mutex。
  • 跨程序同步:Mutex 可以在不同程序之間使用,這一點區別於 lock 關鍵字或 Monitor 類,這些僅限於同一程序內。

2. Mutex 與其他同步機制的比較

同步機制 跨程序 適用範圍
lockMonitor 同一程序內的多執行緒
Mutex 跨程序或同一程序內的多執行緒
Semaphore 控制多個執行緒或程序對資源的訪問
ReaderWriterLockSlim 高效能的讀寫鎖,同一程序內

選擇建議:

  • 如果只需要在同一程序內同步,且對效能有較高要求,推薦使用 lockMonitor)。
  • 如果需要跨程序同步,或者需要確保即使程式異常終止也能釋放資源,選擇 Mutex

3. Mutex 的基本用法

Mutex 的基本操作包括:

  • 建立 Mutex:例項化 Mutex 物件。
  • 獲取 Mutex:透過呼叫 WaitOne 方法請求 Mutex。
  • 釋放 Mutex:呼叫 ReleaseMutex 方法釋放持有的 Mutex。

建立 Mutex

// 建立一個未命名的 Mutex,初始狀態為未獲取
Mutex mutex = new Mutex();

// 建立一個已命名的 Mutex,初始狀態為未獲取
Mutex mutex = new Mutex(false, "Global\\MyMutexName");

獲取和釋放 Mutex

try
{
    // 請求獲取 Mutex
    mutex.WaitOne();

    // 訪問受保護的資源
}
finally
{
    // 確保釋放 Mutex
    mutex.ReleaseMutex();
}

4. 命名 Mutex

透過給 Mutex 指定名稱,可以在不同的程序之間共享同一個 Mutex 例項。這對於需要跨程序同步的場景非常有用。

bool createdNew;
using (Mutex mutex = new Mutex(false, "Global\\MyNamedMutex", out createdNew))
{
    if (!createdNew)
    {
        Console.WriteLine("Mutex 已存在,可能已有另一個例項在執行。");
    }

    // 請求獲取 Mutex
    mutex.WaitOne();

    try
    {
        // 執行需要同步的操作
    }
    finally
    {
        // 釋放 Mutex
        mutex.ReleaseMutex();
    }
}

注意事項:

  • 命名時建議使用 Global\Local\ 字首,以明確 Mutex 的作用範圍。
  • 在 Windows 系統上,Global\ 適用於所有會話,Local\ 僅限當前會話。

5. Mutex 的跨程序同步

Mutex 不僅可以在同一程序內的多個執行緒之間同步,還可以在不同程序之間實現同步。這對於需要確保單一例項執行的應用程式非常有用。

示例場景:

  • 防止多個應用程式例項同時執行。
  • 不同應用程式之間協調對共享資源(如檔案、資料庫)的訪問。

6. 使用 Mutex 的注意事項

  • 確保釋放 Mutex:使用 try...finally 塊確保在訪問結束後釋放 Mutex,避免死鎖。
  • 避免長時間持有 Mutex:儘量縮短持有 Mutex 的時間,減少執行緒等待時間,提高效能。
  • 處理異常:在獲取或釋放 Mutex 時可能會丟擲異常,需做好異常處理。
  • 命名唯一性:命名 Mutex 時確保名稱的唯一性,避免與其他應用程式的 Mutex 衝突。

7. 示例程式碼

以下是一個簡單的示例,演示如何使用 Mutex 在同一程序內的多個執行緒之間同步訪問共享資源。

using System;
using System.Threading;

class Program
{
    // 建立一個命名的 Mutex
    static Mutex mutex = new Mutex(false, "Global\\MyMutexExample");

    static void Main(string[] args)
    {
        // 啟動多個執行緒
        for (int i = 0; i < 5; i++)
        {
            Thread t = new Thread(new ThreadStart(AccessResource));
            t.Name = $"執行緒-{i + 1}";
            t.Start();
        }
    }

    static void AccessResource()
    {
        Console.WriteLine($"{Thread.CurrentThread.Name} 正在等待 Mutex...");

        // 請求獲取 Mutex
        mutex.WaitOne();

        try
        {
            Console.WriteLine($"{Thread.CurrentThread.Name} 獲得 Mutex。正在訪問共享資源...");
            // 模擬訪問共享資源
            Thread.Sleep(2000);
            Console.WriteLine($"{Thread.CurrentThread.Name} 訪問完畢。");
        }
        finally
        {
            // 釋放 Mutex
            mutex.ReleaseMutex();
            Console.WriteLine($"{Thread.CurrentThread.Name} 釋放了 Mutex。");
        }
    }
}

輸出示例:

執行緒-1 正在等待 Mutex...
執行緒-2 正在等待 Mutex...
執行緒-3 正在等待 Mutex...
執行緒-4 正在等待 Mutex...
執行緒-5 正在等待 Mutex...
執行緒-1 獲得 Mutex。正在訪問共享資源...
執行緒-1 訪問完畢。
執行緒-1 釋放了 Mutex。
執行緒-2 獲得 Mutex。正在訪問共享資源...
執行緒-2 訪問完畢。
執行緒-2 釋放了 Mutex。
...

8. 總結

Mutex 是 C# 中一個強大的同步工具,適用於需要在多執行緒甚至多程序之間協調對共享資源的訪問的場景。透過合理使用 Mutex,可以有效避免資料競爭和資源衝突,提高應用程式的穩定性和可靠性。然而,由於 Mutex 的開銷相對較大,且可能導致執行緒阻塞,因此在同一程序內進行簡單的執行緒同步時,優先考慮使用 lockMonitor)等更輕量級的同步機制。

關鍵要點:

  • Mutex 可用於跨執行緒和跨程序同步。
  • 命名 Mutex 允許在不同程序之間共享同一個 Mutex 例項。
  • 使用 WaitOne 獲取 Mutex,使用 ReleaseMutex 釋放 Mutex。
  • 始終確保在 finally 塊中釋放 Mutex,避免死鎖。
  • 適當選擇同步機制,根據實際需求和效能要求做出權衡。

透過深入理解和正確使用 Mutex,可以有效地管理併發訪問,確保程式的正確性和穩定性。

相關文章