【发布时间】:2014-01-17 10:25:46
【问题描述】:
我有一个像下面这样的课程:
class Program
{
static void Main(string[] args)
{
var outputWindow = new OutputWindow();
var threads = new List<Thread>();
Action action = () => outputWindow.Display(20);
for (int i = 0; i < 10; i++)
{
var thread = new Thread(() => action()) {Name = "Thread " + i};
threads.Add(thread);
}
foreach (var thread in threads)
{
thread.Start();
}
}
}
public class OutputWindow
{
public void Display(int x)
{
for (int i = 0; i < x; i++)
{
Console.WriteLine(Thread.CurrentThread.Name + " Outputcounter: " + i);
}
}
}
问题是——这个线程安全吗?这会导致显示方法内的局部变量 i 出现任何竞争条件吗?所有线程是否会按预期增加变量“i”的值(即它会增加值并且不会侵占其他线程的 i 值)
如果这是线程安全的,那么假设在方法中声明的任何局部变量始终是线程安全的并且共享变量是需要同步的变量是否安全?
谢谢, -迈克
【问题讨论】:
-
您有一个局部变量(不是参数)
action(它确实在 lambda 中捕获了另一个局部变量)。然后启动多个线程,为每个线程提供一个新的 lambda,该 lambda 捕获相同的action局部变量。action变量实际上已转换为字段。当然,它毕竟不是那么“本地化”。所以那些局部变量不是线程安全的。当您询问代码中的变量i时,它确实是本地变量。它是在方法内部声明的,它不被任何 lambda 捕获,它不通过ref或out传递,它是一个不可变类型。所以显然没有问题。 -
对不起,我说的是
Display方法中的i。Main方法中的i被捕获在 lambda 中。这显然是有问题的。i变成了一个只会出现在 one 实例中的字段。你可能想要这个:for (int i = 0; i < 10; i++) { int copyOfI = i; var thread = new Thread(() => action()) {Name = "Thread " + copyOfI}; threads.Add(thread); }。 Henk 的回答中也提到了这一点。这样,copyOfI将变成生成类的实例字段,并且该类将有 10 个实例。 -
我认为我之前的评论毕竟是不正确的。可以说
new Thread(() => action()) /* ANONYMOUS LAMBDA HAS STOPPED HERE */ {Name = "Thread " + i /* Not capturing */ };。
标签: c# multithreading local-variables