2010-08-09 100 views
1

我一直花費大約一個小時尋找對我想要完成的事情的共識,但還沒有找到任何結論在特定方向。線程安裝延遲加載時,加載可能會失敗

我的情況是這樣的:

  • 我有一個多線程應用程序(.NET Web服務)
  • 我有使用需要不可忽略的時間來加載對象的類,所以我會喜歡

我以前使用這些構造的方法,以保持它們作爲靜態類成員

  • 是構建這些對象有間歇性故障的可能性較低的代碼靜態構造函數中的對象。如上所述,問題在於,如上所述,構造函數偶爾會失敗,一旦.NET靜態構造函數失敗,整個類都會被徹底清理,直到重新啓動進程。這種方法沒有第二次機會。

    之後最直觀的方法是使用雙重檢查鎖定。關於雙重檢查鎖定的問題,我們討論了很多頁面,並說使用靜態構造函數,我已經這樣做了,但對我來說這似乎不是一種選擇,因爲靜態構造函數具有可能會失敗並導致整個班級失敗。

    我正在考慮使用的實現(簡化,當然)如下。所有班級和會員的名字都是純粹的說明,而不是我實際使用的名稱。這種方法會有問題嗎?任何人都可以提出更好的方法?

    public class LazyMembers 
    { 
        private static volatile XmlDocument s_doc; 
        private static volatile XmlNamespaceManager s_nsmgr; 
        private static readonly object s_lock = new object(); 
    
        private static void EnsureStaticMembers() 
        { 
         if (s_doc == null || s_nsmgr == null) 
         { 
          lock (s_lock) 
          { 
           if (s_doc == null || s_nsmgr == null) 
           { 
            // The following method might fail 
            // with an exception, but if it succeeds, 
            // s_doc and s_nsmgr will be initialized 
            s_doc = LoadDoc(out s_nsmgr); 
           } 
          } 
         } 
        } 
    
        public XmlNamespaceManager NamespaceManager 
        { 
         get 
         { 
          EnsureStaticMembers(); 
          return s_nsmgr; 
         } 
        } 
    
        public XmlDocument GetDocClone() 
        { 
         EnsureStaticMembers(); 
         return (XmlDocument)s_doc.Clone(); 
        } 
    } 
    
  • +0

    在.NET中的雙重檢查鎖定的罪惡?引文? – 2010-08-09 08:54:32

    +0

    Jon Skeets的文章最突出,但我在這裏和那裏看到很多文章和論壇主題,說沒有人真的知道它是否對C#安全和/或建議不要完全使用它。我還沒有看到任何人推薦在.NET上使用它。 – Jimmy 2010-08-09 12:17:25

    +1

    我認爲喬恩做了一個非常體面的分析。它可行,但像「記憶模式」這樣的詞與「平臺版」相結合應該會嚇跑你。 – 2010-08-09 12:44:08

    回答

    2

    如果你使用.NET 4.0,你可以參考Lazy<T>LazyThreadSafetyMode(這取決於你是否要在多線程環境中創建或不是T的少數情況下,在你的情況,你需要參考Lazy<T>(Func<T> func, LazyThreadSafetyMode)構造函數 - here(MSDN)

    否則(如果使用3.5或更低),您可以使用CAS技術創建單個實例而不鎖定。

    事情是這樣的:

    get { 
        if(_instance == null) { 
         var singleton = new Singleton(); 
         if(Interlocked.CompareExchange(ref _instance, singleton, null) != null) { 
          if (singleton is IDisposable) singleton.Dispose(); 
         } 
        } 
        return _instance; 
    } 
    

    然而,在這裏你只能達到LazyThreadSafetyMode.Publications行爲 - 只有一個實例將是可見的其他線程,但很少可以被創建。

    此外,在代碼中檢查null是否應該沒有任何問題 - 它在.NET世界中是安全的(至少在x86機器和相關內存模型中)。 2004年之前Java世界中出現了一些問題,AFAIK。

    +0

    感謝您的意見。 lock()方法看起來更簡單,更合適,因爲我正在處理兩個變量來初始化,但我肯定會考慮使用Interlocked.CompareExchange()來解決未來的問題。我沒有使用.NET 4。0,所以懶惰目前不是一個選項。 – Jimmy 2010-08-09 12:22:59