2016-07-25 64 views
0

我有一個簡單的程序來模擬我的錯誤情況。我有一個單線程類從幾個線程獲取消息。必須阻止執行,直到執行該功能。多線程程序中的鎖()

class Program 
{ 
    private static TestClass test; 
    static void Main(string[] args) 
    { 
     Thread a = new Thread(TestFunctionB); 
     a.Start(); 

     Thread b = new Thread(TestFunctionB); 
     b.Start(); 
    } 

    private static void TestFunctionB() 
    { 
     TestClass test = TestClass.Instance; 
     for (int i = 0; i < 15; i++) 
     { 
      test.Handle(i, Thread.CurrentThread.ManagedThreadId); 
     } 
    } 
} 

class TestClass 
{ 
    private readonly object _lockObject; 
    private static TestClass _instance; 

    private TestClass() 
    { 
     _lockObject = new object(); 
    } 

    public static TestClass Instance 
    { 
     get { return _instance ?? (_instance = new TestClass()); } 
    } 

    private void RunLocked(Action action) 
    { 
     lock (_lockObject) 
     { 
      action.Invoke(); 
     } 
    } 

    public void Handle(int counter, int threadId) 
    { 
     Console.WriteLine("\nThreadId = {0}, counter = {1}\n", threadId, counter); 

     RunLocked(() => 
        { 
         Console.WriteLine("\nFunction Handle ThreadId = {0}, counter = {1}\n", threadId, counter); 

         for (int i = 0; i < 30; i++) 
         { 
          Console.WriteLine("Funktion Handle threadId = {0}, counter = {1}, i = {2}", threadId, counter, i); 
          //Thread.Sleep(100); 
         } 

        }); 

     Console.WriteLine("\nFunction Handle free ThreadId = {0}, counter = {1}\n", threadId, counter); 

    } 


} 

`

我excpect的線程寫輸出一個接一個,但在控制檯的螺紋輸出被混合。鎖定語句不正確?

+0

你預期會發生什麼? 'lock'確保代理的持續時間,其他線程不會獲得它(但不保證它在它之前或之後)。所以第一個線程會完成整個循環(30次迭代),然後是第二個。你想要什麼?打印單個消息?從一個線程和另一個線程恰好一個? – Sinatr

+0

我期待同樣的。但在控制檯窗口我有f.e.來自線程1的20個字符串,然後來自線程2的12個字符串。 – kyy8080

+0

原因可能確實不能很好地實現單例,請參閱[@Scott](http://stackoverflow.com/a/38571048/1997232)回答。最初我雖然得到了這種行爲,但你期望有些不同。 – Sinatr

回答

1

我不知道這是否是您唯一的問題,但get { return _instance ?? (_instance = new TestClass()); }不是原子的,您最終可能會返回多個實例。使用Lazy<T>類保證只創建單例的一個實例。

class TestClass 
{ 
    private readonly object _lockObject; 
    private readonly static Lazy<TestClass> _instance = new Lazy<TestClass>(x=> new TestClass()); 

    private TestClass() 
    { 
     _lockObject = new object(); 
    } 

    public static TestClass Instance 
    { 
     get { return _instance.Value; } 
    } 
    ... 
} 

如果您無權訪問.NET 4.0或更高版本,則需要鎖定您的單例創建。

class TestClass 
{ 
    private readonly object _lockObject; 
    private static readonly object _singletonLock = new Object(); 
    private static TestClass _instance; 

    private TestClass() 
    { 
     _lockObject = new object(); 
    } 

    public static TestClass Instance 
    { 
     get 
     { 
      if(_instance == null) 
      { 
       lock(_singletonLock) 
       { 
        if(_instance == null) 
        { 
         _instance = new TestClass(); 
        } 
       } 
      } 
      return _instance; 
     } 
    } 
    ... 
} 
+0

謝謝。 That works – kyy8080

+0

不要說謝謝,請點擊答案旁邊的複選標記並將其標記爲已接受。 –