Mutex:一種跨 Process 之間的等待機制 - 在 .NET 應用程式的實踐 (上)

名詞定義:
Process - 已被載入到記憶體中執行的 Program 。

應用程式 A 需要等待應用程式 B 完成動作 C 之後,才能繼續執行;換句話說,在 B 執行完 C 之前,應用程式 A 必須被 blocked(阻塞)或 paused(暫停)

這樣的需求,在現代化的作業系統的設計中,有很多種方式可以完成,例如:signal、pipe、mutex、semaphore…等。

 


今天要的達成此目標, Mutex 是這些眾多方式的其中一個簡單易用的機制;透過 .NET 的 Mutex 類別 更不難實現這樣的機制。

這邊直接上兩個 .NET 程式的 C# 實作。

應用程式 A :

var mutexName = "TheMutexTest";

Console.WriteLine($"[MutexTestA] 啟動,開始找尋 MutexTestB 所建立名為 {mutexName} 的 Mutex。");
var waitCount = 0;
Mutex mutex;
while (!Mutex.TryOpenExisting(mutexName, out mutex))
{
    waitCount++;
    Console.WriteLine($"[MutexTestA] 尚未找到 MutexTestB 名稱為 {mutexName} 的 Mutex,會在 1 秒後重試…");
    Thread.Sleep(TimeSpan.FromSeconds(1));

    if (waitCount >= 30)
    {
        Console.WriteLine($"[MutexTestA] 已等了 {waitCount} 秒,找不到 MutexTestB 所建立名稱為 {mutexName} 的 Mutex,結束 MutexTestA");
        return ;
    }
}

using (mutex)
{
    Console.WriteLine($"[MutexTestA] 已找到 MutexTestB 所建立名為 {mutexName} 的 Mutex。");
    var acquired = false;

    try
    {
    	Console.WriteLine($"[MutexTestA] 將透過 MutexTestB 所建立名為 {mutexName} 的 mutex ,等待 MutexTestB 執行完任務 C。");
        mutex.WaitOne();
        acquired = true;
        Console.WriteLine($"[MutexTestA] 等待完成。");
    }
    finally
    {
        if (acquired)
        {
            mutex.ReleaseMutex();
            Console.WriteLine($"[MutexTestA] 已釋放原先 MutexTestB 所建立名為 {mutexName} 的 Mutex");
        }
    }
    
    Console.WriteLine($"[MutexTestA] 來處理該處理的事情...");
    Console.WriteLine($"[MutexTestA] 程式執行結束。");

}

 

應用程式 B:

var mutexName = "TheMutexTest";
using var mutex = new Mutex(false, mutexName, out var createdNew);

Console.WriteLine($"[MutexTestB] 啟動,等待取得 '{mutexName}'。");
Console.WriteLine($"[MutexTestB] 已{(createdNew ? "建立" : "開啟")} 名稱為 {mutexName} 的 Mutex。");

mutex.WaitOne();

try
{
    Console.WriteLine($"[MutexTestB] Mutex 已鎖定,其他 Process 需等待,模擬執行重要任務 C ,執行任務 C 需要花 5 秒完成...");
    Thread.Sleep(TimeSpan.FromSeconds(5));
}
finally
{
    Console.WriteLine($"[MutexTestB] 工作完成,即將釋放名為 {mutexName} 的 Mutex。");
    mutex.ReleaseMutex();
}

Console.WriteLine("[MutexTestB] 程式執行結束。");

 

先將 "應用程式 A" 執行起來後,按照應用程式 A 的應有的執行邏輯,就會透過 Mutex.TryOpenExisting的方法找尋名稱為 "TheMutexTest" 的 Mutex 存不存在目前的系統中,如果找尋 30 次每次間隔 1 秒,這 30 次都沒有尋找到就結束 "應用程式 A" 的執行;而若有尋找到的話,"應用程式 A" 就會等待 "應用程式 B" 執行完任務 C 後再繼續執行後續處理。

接著再將 "應用程式 B" 執行起來,按照應用程式 B 的應有的執行邏輯,會建立一個名為 "TheMutexTest" 的 Mutex 後,並且在開始執行任務 C 之前,透過所建立的 Mutex 鎖定後,才進行任務 C 的處理。

 

測試的過程如下:

在 MutexTestA 執行後才執行 MutexTestB。

並且會觀察到在 MutexTestB 開始執行後,MutexTestA 會開始等待 MutexTestB 執行完 "任務 C" 後才繼續往下執行。

 

不過…在 Windows 上都沒什麼問題,到了 "非 Windows 環境" 就…請看下篇


 


I'm a Microsoft MVP - Developer Technologies (From 2015 ~).
 

MVP_Logo



I focus on the following topics: Xamarin Technology, Azure, Mobile DevOps, and Microsoft EM+S.

If you want to know more about them, welcome to my website:
https://jamestsai.tw 


本部落格文章之圖片相關後製處理皆透過 Techsmith 公司 所贊助其授權使用之 "Snagit" 與 "Snagit Editor" 軟體製作。