2013-08-05 62 views
-1

我有這樣的代碼:這個單例實例成員是否線程安全?

public class Singleton 
{ 
    private static Singleton m_instance; 
    private Singleton() 
    {  

    } 

    public static Singleton Instance 
    { 
     get 
     { 
      if (m_instance == null) 
      { 
       m_instance = new Singleton(); 
      } 
      return m_instance; 
     } 
    } 

    public void CallMe() 
    { 
     // is this function thread safe ? 
    } 
} 

是對的CallMe方法是線程安全的,因爲每一個實例成員函數是線程安全的?或者會在這裏產生一個異常?我看到一個使用鎖的單例代碼,我真的需要嗎?

+2

這可能是有用的:http:// csharpindepth。com/articles/general/singleton.aspx –

+0

它在技術上並不是線程安全的,但該方法什麼都不做,所以不確定這一點。 – EkoostikMartin

+2

[你稱之爲「線程安全」的東西是什麼?](http://blogs.msdn.com/b/ericlippert/archive/2009/10/19/what-is-this-thing-you-call-thread -safe.aspx)「線程安全」本身並不意味着什麼。具體來說,你想確保代碼的正確性?我們需要知道這些(以及更多關於如何實施該方法)以瞭解這種方法是否適用於您的情況。 – Servy

回答

1

沒有任何同步的代碼在沒有任何鎖定機制的情況下不是線程安全的。唯一的線程安全代碼是具有同步機制的代碼。

+0

你能解釋一下嗎?它只是一個非靜態實例成員嗎?並沒有什麼共享accross .. –

+0

@VibinKesavan你說'私人靜態Singleton m_instance;'是非靜態的? – GolfWolf

+3

靜態並不意味着這個類的方法是同步的。 –

0

擴大對丹尼爾的回答是:

private readonly object _threadLock = new Object(); 

public void CallMe() { 
    // whatever happens here is not thread-safe 

    lock(_threadLock) { 

     // this is the simplest form of a locking mechanism 
     // code within the lock-block will be thread-safe 
     // beware of race conditions ... 

    } 
} 

喬恩斯基特是.NET中的權威,以C#。下面是他的線程安全的單實例的分析鏈接:C# in Depth: Implementing Singleton ...

+0

您如何知道該方法的全部內容需要同步?如果沒有對共享狀態的訪問,則不需要在該方法內鎖定任何內容。 – Servy

+0

@Servy:我不知道:) ......這只是一個基於OP問題的簡單示例,並沒有提供任何進一步的細節。你的問題是有效的,只有OP可以回答。 – IAbstract

3

您在這裏有多種問題...

首先使用實例屬性不一定是線程安全的。

如果兩個線程同時請求屬性,那麼他們都可以同時發現m_instance == null to be true`,返回兩個不同的Singleton實例,但只有一個將最終分配給未來調用。

你會需要你的實現是

private static lockObject lock = new Object(); 

public static Singleton Instance 
{ 
    get 
    { 
     if (m_instance != null) return m_instance; 
     lock (lockObject) 
      { 
       if(m_instance != null) return m_instance; 
       return m_instance = new Singleton(); 
      } 
    } 
} 

在靜態構造函數或者簡單地實例化m_instance。

其次,即使在第一個問題解決後,您也不能說CallMe()是線程安全的,我們不知道它在做什麼。

+0

我找到了你,但CallMe在這裏沒有解決。爲什麼我需要鎖定那裏.. –

+0

@VibinKesavan不,但你會使用'Singleton.Instance.CallMe()'和'Instance'部分會遭受問題一,你可以有兩個不同的實例調用'CallMe ()'。 –

+1

@VibinKesavan你知道線程安全的意思嗎? CallMe可能或不可能是線程安全的,具體取決於它是否使用可以在線程之間共享的外部狀態變量。你沒有向我們展示CallMe的代碼,所以我們不能說它是否是線程安全的。 –

2

首先,您的Instance方法不是線程安全的。如果它同時被調用兩次,它將返回兩個不同的實例(並因此破壞單例模式)。

沒有看到它的代碼,不可能知道CallMe是否是線程安全的。

+0

我同意你的第一點,但告訴我CallMe是線程安全與否,如果不是?我怎麼能證明這一點 –

+0

@VibinKesavan「線程安全」本身並不意味着什麼。你需要更具體地說明你期望它做什麼,不做什麼。當你說「線程安全」時,你的意思是什麼?此外,如果沒有實施該方法,或者至少對其做了什麼或不做什麼類型的事情有所瞭解,我們就不能進一步評論。 – Servy

1

有雙重鎖定或嵌套類singletone變種。但在.NET 4.0及以上的最簡單的方法是使用延遲屬性:

public class Singleton 
{ 
    private static Lazy<Singleton> m_instance = new Lazy = new Lazy<Singleton>(); 
    private Singleton() 
    {  

    } 

    public static Singleton Instance 
    { 
     get 
     { 
      return m_instance.Value; 
     } 
    } 

    public void CallMe() 
    { 
     // now its threadsafe 
    } 
} 

懶惰的構造函數有必要時也創造功能,或LazyThreadSafetyMode枚舉

Singleton.Instance現在是線程安全的,但不CallMe()本身。它仍然可以從不同的線程中調用,例如訪問其他類的字段和屬性。這個方法是否在單例實例中並不重要。您應該使用其他機制來確保線程安全。

+0

CallMeMethod怎麼樣? 「實例」方法現在是線程安全的,但不打電話給我,我猜 –

+0

更容易,只是寫:'私人靜態Singleton m_instance =新Singleton();'。它代碼少,同樣也是線程安全的。 – Servy

+0

@Servy:是的。這已經足夠了,但是如果你在.NET 2.0或者更高版本上執行它,它的行爲有點依賴 –

0

這是我會怎麼做的CallMe線程安全:

public class Singleton 
{ 
    private static readonly Singleton instance = new Singleton(); 

    private Singleton() 
    {  

    } 

    public static Singleton Instance { get { return instance; } } 

    public void CallMe() 
    { 
     // Thread Safe 
    } 
} 

換句話說 - 讓核心框架爲您管理的鎖定,互斥體和揮發性的東西。

相關問題