2012-05-16 32 views
2

我有一個示例應用程序,並想知道是否有人可以照亮這一點。當我在for循環中放置一個斷點到調試器中的代碼時,爲什麼它會從一個線程切換到另一個線程?它這樣做在運行時運行應用程序時...請參閱下面的代碼:鎖定問題 - 多線程使循環序列不合

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace TPLSample 
{ 
    class Program 
    { 

     static void Main(string[] args) 
     { 
      Management m = new Management(); 

      Task a = new Task(() => m.Operation1()); 
      a.Start(); 
      Task b = new Task(() => m.Operation2()); 
      b.Start(); 


      Console.ReadLine(); 
     } 
    } 
    public class Management 
    { 
     A a = null; 
     B b = null; 

     public void Operation1() 
     { 
      a = new A(); 

     } 
     public void Operation2() 
     { 
      b = new B(); 
     } 
    } 
    public class A 
    { Client a = new Client(); 
     public A() 
     { 
      while (true) 
      { 
       a.Test("Im AAAAA"); 
      } 
     } 
    } 
    public class B 
    { 
     Client a = new Client(); 
     public B() 
     { 
      while (true) 
      { 
       a.Test("Im BBBBB"); 
      } 
     } 
    } 
    public class Client 
    { 
     Object ibj = new Object(); 


     public void Test(string item) 
     { 
      lock (ibj) 
      { 
       for (int i = 0; i < 200000; i++) 
       { 
        Console.WriteLine(item); 
       } 
      } 

     } 
    } 
} 

這樣做的結果是作爲和BS的混合物。是不是鎖假設阻止線程,結果會按順序結束?我正在編寫的應用程序中發生的情況也是如此,除了WHILE循環永遠運行(每個任務都需要連續輪詢)。請注意,我開始執行兩項任務,因爲如果WHILE循環要永久運行,我不希望有一個WHILE循環阻止另一個循環運行。我如何讓他們順序去CLIENT類中的那個函數?

+0

每個對象都有自己的鎖。如果他們試圖獲得*相同的*鎖定,那麼結果將被序列化。 – jalf

回答

7

發生這種情況的原因是,如果仔細跟蹤對象創建樹,您會注意到每個線程正在使用不同的鎖對象,從而導致您的lock語句無用。

你創建對象會發生這樣的:

    new A() -> new Client() -> new Object() 
       /
new Management() 
       \ 
       new B() -> new Client() -> new Object() 

您使用右側爲鎖的最後兩個對象,你可以清楚地看到,它們是不同的對象。

儘量使鎖靜:

public class Client 
{ 
    static Object ibj = new Object(); 
    ... 

或以其他方式重新考慮你的層次結構,以相同的鎖傳遞給兩個任務。

+0

啊啊。 – Mage

+0

這也有助於我寫的其他應用程序。感謝您的幫助 – Mage

+0

+1:很好的使用'\'和'/'字符。我可能不得不竊取這個想法的答案也:) –

2

每個對象必須有權訪問相同的對象才能使鎖工作。您可以通過將ibj對象設置爲靜態或將其傳遞到客戶端類來實現。

public class Client 
{ 
    static Object ibj = new Object(); 


    public void Test(string item) 
    { 
     lock (ibj) 
     { 
      for (int i = 0; i < 200000; i++) 
      { 
       Console.WriteLine(item); 
      } 
     } 

    } 
}