4

在 C# 规范 4.0 第 7.15.5.1 节中:

请注意,与未捕获的变量不同,捕获的局部变量可以同时暴露给多个执行线程。

“多线程执行”到底是什么意思?这是否意味着多个线程、多个执行路径或其他?

例如

        private static void Main(string[] args)
        {
            Action[] result = new Action[3];
            int x;
            for (int i = 0; i < 3; i++)
            {
                //int x = i * 2 + 1;//this behaves more intuitively.  Outputs 1,3,5
                x = i*2 + 1;
                result[i] = () => { Console.WriteLine(x); };
            }
            foreach (var a in result)
            {
                a(); //outputs 5 each time
            }

            //OR...

            int y = 1;            
            Action one = new Action(() =>
            {
                Console.WriteLine(y);//Outputs 1
                y = 2;                
            });

            Action two = new Action(() =>
            {
                Console.WriteLine(y);//Outputs 2.  Working with same Y
            });

            var t1 = Task.Factory.StartNew(one);
            t1.Wait();
            Task.Factory.StartNew(two);
            Console.Read();
        }

这里x根据x声明的位置表现出不同的行为。在y相同变量被多个线程捕获和使用的情况下,但 IMO 这种行为是直观的。

他们指的是什么?

4

3 回答 3

1

“多线程执行”仅表示多线程;即同时执行的多个线程。如果一个特定变量暴露给多个线程,那么这些线程中的任何一个都可以读取和写入该变量的值。

这是潜在的危险,应尽可能避免。如果您的方案允许,避免这种情况的一种可能性是在您的任务方法中创建变量的本地副本。

于 2013-03-06T14:35:36.020 回答
1

如果您稍微修改代码的第二部分:

        int y = 1;
        Action one = new Action(() =>
        {
            Console.WriteLine(y);//Outputs 1
            y = 2;
        });

        Action two = new Action(() =>
        {
            Console.WriteLine(y);//Outputs 2.  Working with same Y
            y = 1;
        });

        var t1 = Task.Factory.StartNew(one);
        t1 = Task.Factory.StartNew(two);
        t1.Wait();
        t1 = Task.Factory.StartNew(one);
        t1.Wait();
        t1 = Task.Factory.StartNew(two);

        Console.Read();

运行它几次或将其置于循环中。它将输出不同的、看似随机的结果,例如1 1 1 21 2 1 2

多个线程正在访问同一个变量并同时获取设置它,这可能会产生意想不到的结果。

于 2013-03-06T14:43:34.537 回答
1

请参阅下面的链接。

对外部变量 n 的引用据说在创建委托时被捕获。与局部变量不同,捕获变量的生命周期会延长,直到引用匿名方法的委托有资格进行垃圾回收。

换句话说,变量的内存位置在创建方法时被捕获,然后共享给该方法。就像一个线程可以访问该变量减去匿名方法一样。在某些情况下会出现编译器警告,它会建议您移动到本地临时变量,以免造成意外后果。

MSDN 匿名方法

于 2013-03-06T15:06:54.150 回答