C#2.0线程问题(匿名方法)
本文关键字:方法 线程 问题 C#2 | 更新日期: 2023-09-27 17:47:46
我有一个简单的应用程序,代码如下:
FileInfo[] files = (new DirectoryInfo(initialDirectory)).GetFiles();
List<Thread> threads = new List<Thread>(files.Length);
foreach (FileInfo f in files)
{
Thread t = new Thread(delegate()
{
Console.WriteLine(f.FullName);
});
threads.Add(t);
}
foreach (Thread t in threads)
t.Start();
比方说,在"I=initialDirectory"目录中,我有3个文件。这个应用程序应该创建3个线程,每个线程打印出一个文件名;但是,每个线程都会打印出"files"数组中最后一个文件的名称。
为什么会这样?为什么当前文件"f"变量没有在匿名方法中正确设置?
匿名方法在封闭块中保留对变量的引用,而不是变量的实际值。
当方法实际执行时(当您启动线程时),f
已被分配为指向集合中的最后一个值,因此所有3个线程都打印最后的值。
以下是一些关于C#中匿名方法的好文章,以及编译器将生成的代码:
http://blogs.msdn.com/oldnewthing/archive/2006/08/02/686456.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/03/687529.aspx
http://blogs.msdn.com/oldnewthing/archive/2006/08/04/688527.aspx
我想如果你这样做了:
foreach(文件中的FileInfo f){文件信息f2=f//循环中声明的变量线程t=新线程(delegate){Console.WriteLine(f2.FullName);});螺纹。加(t);}
它会按照你想要的方式工作。
这是因为f.FullName
是对变量的引用,而不是值(这就是您尝试使用它的方式)。当您真正启动线程时,f.FullName一直递增到数组的末尾。
无论如何,为什么要在这里重复两次呢?
foreach (FileInfo f in files)
{
Thread t = new Thread(delegate()
{
Console.WriteLine(f.FullName);
});
threads.Add(t);
t.Start();
}
然而,这仍然是错误的,甚至可能更糟,因为您现在有了一个竞争条件来查看哪个线程运行得更快:写入控制台项或迭代到下一个FileInfo。
这是因为迭代器(foreach)的底层代码在线程启动之前已经"迭代"了List中的所有值。。。因此,当它们开始时,迭代器"指向"的值是列表中的最后一个。。。
而是在迭代中启动线程。。。。
foreach (FileInfo f in files)
{
string filName = f.FullName;
Thread t = new Thread(delegate()
{ Console.WriteLine(filName); });
t.Start();
}
我认为这里不可能出现竞争,因为没有可以从所有线程访问的共享内存。
以下内容也同样有效。
Thread t = new Thread(delegate()
{
string name = f.Name;
Console.WriteLine(name);
});