C#多线程:按值传递还是按引用传递?

3
我在网上看到一段代码,它声称像这样调用线程会导致不确定的输出,如“0223557799”之类的(你懂的)。
for (int i = 0; i < 10; i++)
   new Thread (() => Console.Write (i)).Start();

这是给出的原因:
“问题在于i变量在整个循环期间都指向同一内存位置。因此,每个线程在运行时调用Console.Write时会对一个值可能会改变的变量进行操作!”
但是,按照惯例,当按值传递参数时,每个新的Thread调用都应该将i作为其增量顺序发送,对吗?只有如果值是通过引用传递的,上述原因才成立。那么,在C#多线程中,值是按引用传递的吗?
我是新手,请理解如果问题比较幼稚。

3
将“int temp = i;”放在循环内,并传递变量temp,Slaks是正确的。 - terrybozzio
2个回答

11

您的程序等同于以下程序:

class Locals
{
    public int i;
    public void M() { Console.Write(this.i);
}

...
Locals locals = new Locals();
for (locals.i = 0; locals.i < 10; locals.i++)
  new Thread (locals.M).Start();

现在你清楚为什么会得到你所看到的结果了吗?传递的不是 i 值,而是 locals 按引用传递给每个线程。每个线程都在 共享 locals.i,因此可以看到 locals.i当前 值,而不是线程创建时的 i 值。


8

这里涉及到一个以上的问题。其中一个问题是for()循环变量捕获问题,这在这篇博客文章中有所描述。这往往会产生“10”作为输出,但是并不能保证发生这种情况,因为在线程迭代循环时,可能会有一个线程执行。

但这个程序也存在着核心的线程问题,没有任何保证线程将按预期顺序调用Console.Write()。它只是可能,但一个线程可能领先于另一个线程并获取保护控制台的锁定。这就是一个已知的问题,称为“线程竞争”。


2
C# 5 中的更改仅适用于 foreach 循环,而不适用于 for 循环。 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接