多线程BUG捕捉之:匿名函数带来的问题

最近有一个隐藏的BUG,是因为使用匿名函数导致的。

     要重现该BUG,可以先查看如下两个程序。

     第一个:

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                DisplayInt(i);
            }
            Console.Read();
        }

        private static void DisplayInt(int i)
        {
            MethodInvoker mi = new MethodInvoker(delegate()
            {
                Thread.Sleep(1000);
                Console.Write(i);
            });
            mi.BeginInvoke(null, null);
        }
    }

    输出为:0 1 2 …… 9

   

    第二个程序,采用匿名函数的方式来完成相同的功能:

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                MethodInvoker mi = new MethodInvoker(delegate()
                {
                 Thread.Sleep(1000);
                 Console.Write(i);
                });
                mi.BeginInvoke(null, null);
            }
            Console.Read();
        }

    }

    结果发现,事情并不是我们想象的那样,而是

    输出为:10 10 10 …… 10

   

    分析其原因,在第二个程序中,虽然匿名函数和第一个程序中的DisplayInt完成的是一样的功能。但是这个功能本身是要新起一个线程来执行打印i。而i这个参数,是由主线程传入进去的。那么,可以理解为,在第二个程序中,主线程中的FOR循环已经执行完毕的时候,FOR循环所起的10个工作线程,还没有启动,当它们由.NET运行时环境自行决定启动的时候(当然,这个事件会很短),FOR循环中的i已经变成10,所以,第二个程序产生了上面的结果。

    当然,我想,这个结果应该也不唯一,这完全取决于匿名函数中的线程执行的时候FOR循环是否已经执行完毕了。

    回过头来,考虑第一段代码,因为不是使用的匿名函数,所以内存地址中,保留了一个i的副本,故程序执行正确。

 

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭