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

分享到噗浪!

前幾天在寫主控台程式 (Console Application) 時突然想到一個避免程式在同時間重複執行的機制,在噗浪發問與自行研究過後發現最彈性的實做方式是利用 .NET 內建的 Mutex 類別進行實做,幾乎任何情況下都能輕易實做程式不重複執行的目的,包括單機環境與多人使用的伺服器環境。

Mutex 類別有兩種用法:

  1. 不具名 Mutex 用法:在單一程序內實做 Mutex 機制 [ 可參考 MSDN 的 Mutex 程式範例 ]
  2. 具名的 Mutex 用法:在整台主機系統內實做 Mutex 機制

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

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

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

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

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

依據上述需求,我實做出以下程式:

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 類別有關的細節請各位細讀 MSDN 文件。

相關連結

  

此文章由 will 發表於 2009/10/23 下午 11:13:01

永久連結 | 評論 (2) | 此文章的RSSRSS comment feed |

分類: C# | .Net

標籤: , , , ,

評論

十月 27. 2009 12:54

ChrisTorng

我好奇,是只有 "\" 這一個字元不能用,還是「目前系統使用之路徑分隔符號」不能用? 畢竟還是有差...
另外,不知是否有分大小寫...如果會區分的話,參數一樣的判斷就有可能破功 (印象中 args[0] 是執行程式名稱,大小寫均可)...如果參數中有路徑,還有可以用短檔名、捷徑等方式騙過...
以上都是吹毛求疵,不用理我...^_^

ChrisTorng 台灣

十月 27. 2009 23:06

Will 保哥

ChrisTorng:

看的出您是個嚴僅的人,如果您有空研究的話,非常歡迎你來我部落格留言告知您的研究結果。 ^_^

Will 保哥 台灣

新增評論


( 您輸入的Email不會顯示於網站上 )

  Country flag

biuquote
  • 評論
  • 線上預覽
Loading