2012-03-30 80 views
1

所以這裏就是我想要做的事:如何使這個C#類單身,線程安全

public static class MyClass 
{ 

    private Dictionary<string,IDisposable> dict = null; 

    static MyClass() 
    { 
     dict = new Dictionary<string,IDisposable>(); 

     // i fill up the dictionary in a loop here 
     // 
    } 

    public static UseDictionary(string name) 
    { 
     var obj = dict[name]   
     obj.DoSomeAction();   
    } 

} 

static void Main(string[] args) 
{ 
    Parallel.For(0, 1000, x => 
    {    
     // assuming 'name' does exist in the dictionary 
     MyClass.UseDictionary("name"); // randomly throws null reference errors 
    }); 
} 

我基本上希望有這個類的一個實例,這將初始化字典只有一次( IDisposable項目是一個昂貴的遠程連接我打開,我想打開它只有一次)

此類將用於不同的asp.net頁面。所以我希望它是線程安全和單身。我想在靜態構造函數中初始化字典將使它只能被調用一次,並且線程安全,不知道爲什麼我不斷收到錯誤。有任何想法嗎?

+1

也許分享錯誤消息的確切文本可能對嘗試幫助您的人有益。 – 2012-03-30 02:14:35

+1

從示例中,唯一可能導致的問題是由多個線程同時調用的DoSomething方法存在一些問題。 – 2012-03-30 02:21:44

+0

可能的重複[這是一個有效的,懶惰的,線程安全的Singleton實現C#?](http://stackoverflow.com/questions/2615527/is-this-a-valid-lazy-thread-safe-singleton- c) – Joe 2012-03-30 02:26:43

回答

2

我@Leonardo加西亞克雷斯波的評論表示贊同。從我在這裏看到的,你只能在靜態構造函數中寫入字典,而每個應用程序域只能調用一次。其他所有內容都是讀取,如果集合未修改,通用字典支持多個閱讀器。問題只能在於被調用的代碼中。它也需要是線程安全的。或者,您可以使用另一個關聯鎖的字典並鎖定相應的鎖,以便一次只能調用一個非線程安全的實例。

public static class MyClass 
{ 
    public static Dictionary<string,SomeDisposableClass> dict = null; 
    public static Dictionary<string,object> locks = null; 

    static MyClass() 
    { 
     // populate the dictionary 
     locks = new Dictionary<string,object>(); 
     foreach (var key in dict.Keys) 
     { 
      locks[key] = new object(); 
     } 
    } 

    public static void UseDictionary(string name) 
    { 
     var obj = dict[name]; 
     var sync = locks[name]; 
     lock(sync) 
     { 
      obj.DoSomething(); 
     } 
    } 
} 

您也可以使用Singleton模式,但如果你只是有可能不是必要的一個靜態方法。我會注意到,這將是可怕的解決任何使用這個類的代碼。

而且,是的,我知道如果使用name的相同值調用1000次,它將是單線程的。如果被調用的方法不是線程安全的,那麼這是你可以做的最好的。這樣,至少,您可以讓多個線程同時運行name的不同值,因爲它們鎖定了不同的對象。

+0

我確實有10-20多個靜態方法,但我只是在這裏展示了一個例子。我認爲這個問題可能出現在你說的DoSomething方法中。我想知道如果這是正確的模式雖然。我試圖完成的是使用這個類作爲連接打開的唯一的地方。這個類的任何消費者不需要擔心打開到不同服務器的連接。有沒有其他的模式可以用來設計這個課程? – newbie 2012-03-30 03:51:56

+0

是Sigleton模式更好還是使用像我這樣的靜態構造函數?特別是對於asp.net網頁? – newbie 2012-03-30 03:56:54

+0

@newbie我的首選將是它不是一個單身或靜態類。是的,把邏輯放在一個地方,但要讓班級成爲普通班級。如果操作確實很昂貴,而且我需要證明性能確實是一個問題,那麼您可以考慮緩存或依賴注入,其中可以注入單個實例。我擔心你的連接在對象的整個生命週期中無法存活,並且可能會選擇讓它們在每個頁面上重新創建。 – tvanfosson 2012-03-30 10:53:56

0

看這裏http://www.codeproject.com/Articles/14026/Generic-Singleton-Pattern-using-Reflection-in-C

對不起,:'(到地獄的道路是充滿善意

我只是想給其他一個簡單的選擇,而不在我進入的細節

時間也有問題,我後Multi web services so multi singleton終於創建我自己的版本

這真的工作,我有50左右的內部應用程序和一些外部提供商使用它

那麼總結 在c#中完成對單例模式和diferents示例的檢查想法得出的結論是,一個好的實現是基於內部類來創建一個實例是保證調用構造函數完成一旦時間雖然單CLAS從多個線程調用,所以只是有一個實例

在vb.net簡化

Public NotInheritable Class ServiceProxySingleton 

Private Sub New() 
End Sub 

Public Shared Function GetInstance() As ServiceProxySingleton 
    Return NestedSingletonService._instance 
End Function 

    ' Internal class 
    Class NestedSingletonService 
    Friend Shared ReadOnly _instance As [SingletonClass] = New [SingletonClass]() 
    Shared Sub New() 
    End Sub 
    End Class 

End Class 
+0

這是一個非常沉重的版本,需要下載某人elses我建議的代碼。通常最好是製作自己的代碼並理解它,而不是下載並插入它。 (在這樣的小修復的情況下) – 2012-03-30 02:23:55

+2

請不要張貼鏈接作爲答案,也解釋您的鏈接的內容,以便如果該鏈接曾經下降,仍然有你的答案的記錄。 – 2012-03-30 02:24:51

+0

以及鏈接是純粹的信息提供理解或複製它取決於每個 – 2012-03-30 20:16:41

0

下面的代碼應該是線程安全的,監守靜態字段初始

private static readonly Dictionary<string,IDisposable> dict = 
              CreateAndInitializeDictionary(); 
private static Dictionary<string,IDisposable> CreateAndInitializeDictionary() { 
    var d = new Dictionary<string,IDisposable>(); 
    .... // here add items 
    return d; 
} 

並檢閱碼一次我意識到,您的實現也是線程安全後.NET保證線程安全。這個問題應該在DoSomething() :)

0

你可以在你的類上使用同步屬性。這是我爲我的一個班級所做的。我包括評論,因爲他們解釋了這種情況。

[Synchronization] 
public class IprServerController : ContextBoundObject 
{ 
    // We need to worry about things like a user deleting a route at the same time that another user is starting one. 
    // So, instead of trying to lock appropriately throughout the class, we can lock declaratively, by using the 
    // Synchronization attribute and deriving from ContextBoundObject. Now only one thread can execute methods on 
    // this class at a time.