我有一个类,就像下面这样:
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
传递,它是一个不可变类型。因此,它显然不会出现问题。 - Jeppe Stig NielsenDisplay
方法中的i
。Main
方法中的i
被lambda捕获了,这显然是有问题的。i
被转换成一个字段,它只会在一个实例中出现。你可能想要这样做:for(int i = 0; i <10; i ++){ int copyOfI = i; var thread = new Thread(()=> action()){Name =“Thread”+ copyOfI}; threads.Add(thread); }
。这也在Henk的答案中提到过。这样一来,copyOfI
将成为生成类上的一个实例字段,并且将有十个该类的实例。 - Jeppe Stig Nielsennew Thread(() => action()) /* 匿名 lambda 在此处停止 */ {Name = "Thread " + i /* 不会捕获 */ };
。 - Jeppe Stig Nielsen