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();