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"变量没有在匿名方法中正确设置?

C#2.0线程问题(匿名方法)

匿名方法在封闭块中保留对变量的引用,而不是变量的实际值。

当方法实际执行时(当您启动线程时),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);
    });