2013-02-28 64 views
1

我有下面的代碼產生不一致的輸出。不一致的線程

string text = "t1"; 
new Thread (() => Console.WriteLine (text)).Start(); 

//Thread.Sleep(1); 

text = "t2"; 
new Thread (() => Console.WriteLine (text)).Start(); 

有時會產生t1和t2,有時會產生雙t2。 我現在在想什麼呢。當它的輸出是double t2時,第一個線程的捕獲變量值是t2,因爲它是在最後一次變量賦值之後開始的。我對嗎?

注意:我在慢速機器上運行此代碼。

+3

是的,你說得對 – MarcinJuraszek 2013-02-28 16:14:40

+0

這就是爲什麼ReSharper的抱怨修改「倒閉潮」的時候。如果在單獨線程中啓動lambda之後更改該變量,則始終創建傳遞給lambda的參數的副本,以解決此問題。 – 2013-02-28 16:17:49

+0

我已經添加了單線程代碼來演示@MatthewWatson提到的問題作爲參考的答案。 – 2013-02-28 16:41:51

回答

3

您是對的;請參閱維基百科上的race conditions

根據定義,線程不會同步執行,所以您不應該期望代碼的順序能夠明確地確定程序的行爲。

+0

謝謝! 'Race Condition'是我正在尋找的術語。 :) – 2013-02-28 16:24:43

+0

正確的期限和關於訂購電話的說明。 @FreddieFabregas,請關注Matthew Watson的評論 - 您的代碼問題是由關閉引起的,並且由於競爭條件而暴露。如果不是線程而是簡單地緩存lambda並稍後在同一線程中調用它,那麼您可能容易產生類似混淆的行爲。 – 2013-02-28 16:31:27

+0

@AlexeiLevenkov,是的。我會注意到這一點。 – 2013-02-28 16:39:09

1

是的,這是一個簡單的多線程問題。

雖然第一個線程甚至沒有啓動,但您可以更改文本變量的值。 然後第一個線程以新值開始,並且您有一個雙't2'

1

「有時它是生產雙T2」

文本的價值已經被之前的第一

new Thread (() => Console.WriteLine (text)).Start(); 

已執行

如果你想保持一致,變化改爲「T2」:

string text = "t1"; 
new Thread (() => Console.WriteLine (text)).Start(); 

//Thread.Sleep(1); 

string text2 = "t2"; 
new Thread (() => Console.WriteLine (text2)).Start(); 
+0

+1用於顯示如何避免修改閉包中的值(通過捕獲2個不同的變量)。 – 2013-02-28 16:32:35

-1

因此,最簡單的方法是對變量使用鎖

這樣可以防止一個線程訪問的變量,而它由一個又一個

+0

-1。添加任何類型的'lock'語句都不會解決現有示例中的任何問題,因爲這個問題主要是由關閉引起的並由線程暴露。另一方面,如果你顯示能夠正確使用'lock'的樣本,那麼它可以成爲一個答案。 – 2013-02-28 16:27:44

1

是的,你有競爭狀態,每個人都提到了。

在你的情況下,它暴露了大多數人並不期望的閉包行爲:閉包捕獲變量,而不是它的值。這個問題可以在單個線程的情況下很容易地顯示:

string text = "t1"; 
Action a1 = () => Console.WriteLine (text); 
a1(); // prints "t1" 
text = "t2"; 
Action a2 =() => Console.WriteLine (text) ; 

a1(); // prints "t2" 
a2();