• 使用Mutex實現單一程式執行個體的注意事項(转)


    相信大家都知道在.NET程式中若要實現單一程式執行個體,一般來說有幾種方法,像是去判斷是否已經有開啟的Process是相同的程式、用Mutex與Semaphore之類的技術來判斷是否程式正在開啟。但是很多網路上的文章都忽略了在用Mutex實現單一程式執行個體時,其實會有些必須要注意的地方,導致於在實際運用上沒有發揮到該有的效果。

    以一個簡單的例子來看,一般我們在網路上常看到的使用方式大概就像下面的程式碼片段類似,建構Mutex時就會回傳該Mutex是否已經存在,利用該回傳值來決定程式應該繼續開啟還是關閉。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace WindowsFormsApplication10
    {
        static class Program
        {
            /// <summary>
            /// The main entry point for the application.
            /// </summary>
            [STAThread]
            static void Main()
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
    
                Boolean bCreatedNew;
    
                //Create a new mutex using specific mutex name
                Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew);
    
                if (bCreatedNew)
                    Application.Run(new Form1());
            }
        }
    }

    這樣的程式到底有什麼樣的問題呢?有興趣的可以試著建置Release的程式看看,其實這樣的程式在某些情況下會在Release模式下失效,Debug的運作卻是正常的,若試不出來的可以再加上個GC.Collect試試,會更容易重現。

    ...
    Boolean bCreatedNew;
    
    //Create a new mutex using specific mutex name
    Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew);
    
    GC.Collect();
    
    if (bCreatedNew)
        Application.Run(new Form1());
    ...

    之所以會有這樣的問題,是因為Mutex在Release模式下被GC給回收了,而Debug模式下因為便於開發人員除錯,據說有將GC的周期給拉長,所以不容易重現。那這樣的問題要怎麼樣解決呢?這邊筆者有整理了幾種方法。

    一個方法就是把Mutex給拉出來成為類別成員。

    ...
    static Mutex m;
    
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
    
        Boolean bCreatedNew;
    
        //Create a new mutex using specific mutex name
        m = new Mutex(false, "myUniqueName", out bCreatedNew);
        GC.Collect();
    
        if (bCreatedNew)
            Application.Run(new Form1());
    }
    ...

    另一個方法就是讓Mutex不要被GC回收掉,像是在程式最後明確呼叫Dispose,讓GC知道該Mutex仍在使用。

    ...
    Boolean bCreatedNew;
    
    //Create a new mutex using specific mutex name
    Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew);
    
    GC.Collect();
    
    if (bCreatedNew)
        Application.Run(new Form1());
    
    m.Dispose();
    ...

    也可以用using或是try...finally之類的語法將Mutex給hold住。

    ...
    Boolean bCreatedNew;
    
    //Create a new mutex using specific mutex name
    using (Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew))
    {
        GC.Collect();
    
        if (bCreatedNew)
            Application.Run(new Form1());
    }
    ...

    或是把Mutex的用法寫的比較正規一點,加上WaitOne與ReleaseMutex去明確控制Mutex的作用範圍。

    ...
    Boolean bCreatedNew;
    
    //Create a new mutex using specific mutex name
    Mutex m = new Mutex(false, "myUniqueName", out bCreatedNew);
    
    m.WaitOne();
    GC.Collect();
    
    if (bCreatedNew)
        Application.Run(new Form1());
    
    m.ReleaseMutex();
    ...
  • 相关阅读:
    Sun:收购MySQL是现代软件史上最重要收购[ZT]
    SCI2012年收录的中文期刊
    Elsevier期刊投稿状态
    医学图像SCI
    贝叶斯法则,先验概率,后验概率,最大后验概率
    医学图像处理与分析方面的大牛
    2013 EI检索的国内期刊
    ICIP EMBC IUS 2013
    香港中文大学第六十九届颁授学位典礼 校长赠言 我默祷你们都能不负此生
    自动生成参考文献编号
  • 原文地址:https://www.cnblogs.com/MLGB/p/4465901.html
Copyright © 2020-2023  润新知