2011-12-26 102 views
0

我有理解意想不到輸出下面的程序很難本地變量傳:關於線程

class ThreadTest 
{ 
    static void Main() 
    { 
      for(int i = 0; i < 10; i++) 
       new Thread(() => Console.Write(i)).Start(); 
    } 

} 

查詢:在不同的線程中運行 不同代碼單獨有堆?如果是,那麼變量應該保留它們的值,因爲int是一個值類型?

+0

這一直是一個問題,如果你是新的匿名委託,你不知道代碼如何被幕後產生。我確信每個.NET開發者都應該面對這個問題,至少有一次。 –

回答

3

每個線程都有自己的堆棧。你面臨的問題與堆棧無關。問題在於它爲匿名代理生成代碼的方式。使用像重繪器這樣的工具來了解它生成的代碼。下面將解決您的問題:

static void Main() 
     { 
      for (int i = 0; i < 10; i++) 
      { 
       int capture = i; 
       new Thread(() => Console.Write(capture)).Start(); 
      } 
     } 

引擎蓋下

每當你使用一個變量來自外部範圍(在你的情況下,變量i)在匿名委託,編譯器生成一個封裝了一類新匿名函數以及它從外部作用域使用的數據。所以在你的情況下,生成的類包含 - 一個函數和數據成員來捕獲變量i的值。類定義看起來類似:

class SomeClass 
{ 
    public int i { get; set; } 

    public void Write() 
    { 
     Console.WriteLine(i); 
    } 
} 

編譯如下重新編寫代碼:

SomeClass someObj = new SomeClass(); 
for (int i = 0; i < 10; i++) 
{ 
    someObj.i = i; 
    new Thread(someObj.Write).Start(); 
} 

,因此問題 - 你所面對。當你捕捉一個變量,編譯器將執行以下操作:

for (int i = 0; i < 10; i++) 
{ 
    SomeClass someObj = new SomeClass(); 
    someObj.i = i; 
    new Thread(someObj.Write).Start(); 
} 

注意在SomeClass的實例化的差異。當捕獲一個變量時,它會創建與迭代次數一樣多的實例。如果您沒有捕獲變量,它會嘗試在所有迭代中使用相同的實例。

希望以上的解​​釋會澄清你的疑問。

感謝

+1

ILSpy是Reflector的免費替代品。 – Amy

2

是的,線程有自己的堆棧。但在這裏你也有一個變量捕獲的問題。嘗試將代碼更改爲:

class ThreadTest 
{ 
    static void Main() 
    { 
     for(int i = 0; i < 10; i++) 
     { 
       int j = i; 
       new Thread(() => Console.Write(j)).Start(); 
     } 
    } 
} 

請注意輸出的變化?每個線程都以引用變量的方式啓動,而不是值。當我插入int j = i;行時,我們打破了變量捕獲。線程的意外輸出與閉包無關。

+0

引用上面的代碼從c#4.o簡而言之,當我嘗試上面的代碼,我不知道是什麼原因,我不知道每10次運行我得到一個輸出像0213456789,我會檢查代碼在晚上有反光板,因爲這種可用性在我們的工作場所是不被允許的。 – mohits00691

+1

線程不保證以任何特定順序運行。這很正常。 – Amy