﻿# 如何避免相同的 ConsoleApp 或 WinForm 同時間重複執行

前幾天在寫主控台程式 (Console Application) 時突然想到一個避免程式在同時間重複執行的機制，[在噗浪發問](http://www.plurk.com/p/2bfd73)與自行研究過後發現最彈性的實做方式是利用 .NET 內建的 [Mutex 類別](http://msdn.microsoft.com/zh-tw/library/system.threading.mutex.aspx)進行實做，幾乎任何情況下都能輕易實做程式不重複執行的目的，包括單機環境與多人使用的伺服器環境。

[Mutex 類別](http://msdn.microsoft.com/zh-tw/library/system.threading.mutex.aspx)有兩種用法：

1.  **不具名 Mutex 用法**：在單一程序內實做 Mutex 機制 \[ 可參考 MSDN 的 [Mutex](http://msdn.microsoft.com/zh-tw/library/system.threading.mutex.aspx) 程式範例 \]
2.  **具名的 Mutex 用法**：在整台主機系統內實做 Mutex 機制

**不具名 Mutex 用法**較常實做在同一個程序內為了確保資源僅被單一執行緒使用，才會利用**不具名 Mutex 的物件**進行互斥處理。

其中**具名的 Mutex 用法**還包括兩種使用範圍：

1.  在同壹台主機相同使用者的範圍內進行 Mutex 互斥 ( 採用 Local\\ 前置詞 )
2.  在同壹台主機所有使用者的範圍內進行 Mutex 互斥( 採用 Global\\ 前置詞 )

我在實驗的時候設定了一個較複雜的情境，描述如下：

-   要在同一台主機內，不管有多少 User 登入電腦執行同一支程式，都要進行互斥(Mutex)處理
-   程式若是在相同目錄下才需要進行互斥處理，如果程式複製到不同的目錄就不需要進行互斥處理
-   由於該 Console 程式有傳入參數，當輸入參數完全相同時必須要進行互斥處理

依據上述需求，我實做出以下程式：

```csharp
static void Main(string[] args)
{
  bool is_createdNew1;
  bool is_createdNew2;
  Mutex mu1 = null;
  Mutex mu2 = null;

  try
  {
    #region 檢查程式是否重複執行

    // 第一關：在同目錄執行相同程式的情況下不允許重複執行
    string mutexName1 = Process.GetCurrentProcess().MainModule.FileName
                .Replace(Path.DirectorySeparatorChar, '_');
    mu1 = new Mutex(true, "Global\\" + mutexName1, out is_createdNew1);
    if (!is_createdNew1)
      return;

    // 第二關：在完全相同的傳入參數下不允許重複執行，避免數據重複計算
    string mutexName2 = "Args_" + String.Join("_", args)
							.Replace(Path.DirectorySeparatorChar, '_');
    mu2 = new Mutex(true, "Global\\" + mutexName2, out is_createdNew2);
    if (!is_createdNew2)
      return;

    #endregion

    DoSomething();
  }
  catch (Exception ex)
  {
    throw ex;
  }
  finally
  {
  }
}
```

如果你僅需限制互斥的範圍只需在「同使用者」的範圍內，只需將 Mutex 名稱的 Global\\ 改成 Local\\ 即可。如果你還有更多其他條件需判斷，只需要多建立幾可 Mutex 進行判斷，所以這樣的設計方式十分彈性，可以自行組合出多種變化。

眼尖的讀者可能會發現從上述程式在設定 Mutex 名稱時多做了一些手腳，也就是必須將所有反斜線符號 ( \\ ) 都換成底線符號 ( \_ )，因為反斜線 ( \\ ) 符號在 Mutex 中有特殊意義，另外從 MSDN 文件中也發現 Mutex 名稱長度也不得大於 260 個字元，條列整理如下：

**Mutex 命名限制**

-   Mutex 名稱長度不得大於 260 個字元
-   Mutex 名稱不能使用反斜線 ( \\ ) 符號

其他與 [Mutex 類別](http://msdn.microsoft.com/zh-tw/library/system.threading.mutex.aspx)有關的細節請各位細讀 MSDN 文件。

**相關連結**

-   [Mutex Class](http://msdn.microsoft.com/en-us/library/system.threading.mutex.aspx)  /  [Mutex 類別](http://msdn.microsoft.com/zh-tw/library/system.threading.mutex.aspx)
-   [Mutex 建構函式 (Boolean, String, Boolean)](http://msdn.microsoft.com/zh-tw/library/bwe34f1k.aspx)
-   [Mutex](http://msdn.microsoft.com/zh-tw/library/hw29w7t1.aspx) ( .NET Framework 開發人員手冊 )
-   [CreateMutex Function](http://msdn.microsoft.com/en-us/library/ms682411\(VS.85\).aspx) ( Win32 and COM Development )
-   \[VB2005\]在 Sub Main 的 Console 或 Window 應用程式限定為單一執行個體應用程式
-   [\[C#.NET\]\[VB.NET\]\[VB6\] 如何禁止程式重覆執行 / System.Threading.Mutex](https://dotblogs.com.tw/yc421206/2009/08/08/9948)
-   [\[C#\]EXE執行檔單獨執行以及已經執行時做還原](https://dotblogs.com.tw/chou/2009/02/16/7187)
-   [Single-Instance Applications and C#](http://blogs.msdn.com/tyler_whitney/archive/2005/11/28/497604.aspx)
