2011-09-03 47 views
6

假設我有下面的C#類多個線程同時調用相同的對象。它會導致問題嗎?

class MyClass 
{ 
    private int _i; 
    private object _locker = new object(); 

    public void DoSomething() 
    { 
     var b = 2; 

     // some work that depends on b being 2 

     lock(_locker) 
     { 
      _i = 3; 
     } 

     // some more work 

     b = -1; 

     // some more work 
    } 
} 

我使用這種方式,

//Usage: 

var myobject = new MyClass(); 
new Thread(new ThreadStart(() => myobject.DoSomething())).Start(); 
new Thread(new ThreadStart(() => myobject.DoSomething())).Start(); 

下列順序發生的呢?

Thread 1 is halfway through its work. 
Thread 2 just starts. Sets b = 2. 
Thread 1 sets b = -1. 
Thread 2 is confused because it expected b to be 2 but its -1. 

重要的一點是,b是一個局部變量。這兩個線程是否可以訪問b的同一個實例?我知道對於實例變量_i,會發生這種情況。因此,lock構造。但我不確定是否需要爲局部變量進行鎖定。

+1

'b'是本地的,因此對每個線程都是唯一的。 –

+1

如果'_i'剛剛分配了兩次相同的值,爲什麼不考慮在啓動線程之前在非併發的代碼段中移動賦值? (或者當他們完成時) –

回答

11

當調用者輸入方法DoSomething()時,局部變量將被放入堆棧。每個線程在一個單獨的堆棧上運行,並將獲得自己獨特的局部變量。

這部分從Wikipedia for thread local storage適用於C#線程,以及:

換句話說,當通過螺紋從 稱爲在靜態或全局變量數據是通常總是 位於在相同的存儲器位置,相同的過程。但是堆棧上的變量對於線程來說是本地的,因爲每個線程都有自己的堆棧,它們位於不同的內存位置 位置。

+2

我在我的例子中知道'b'是一個原始類型。但是,假設'b'是某個類的對象。我正在修改它的財產。現在'b'是一個引用類型,它是否仍然在每個線程的本地堆棧上?我認爲引用類型的對象存儲在所有線程共享的堆內存中... –

+3

@Amith:如果在方法內創建對象,*對象引用*仍然存儲在堆棧中,而對象本身將被分配在堆上。從根本上說,這不會改變任何事情,因爲每個線程都有自己的對象引用堆中的不同對象。 – BrokenGlass

+0

如果b是引用類型並作爲方法參數傳遞給該方法,該怎麼辦? – Harindaka

相關問題