C#中的简单线程

时间:2012-06-19 21:32:15

标签: c# multithreading

  

可能重复:
  C# Captured Variable In Loop

我正在开发一些简单的线程应用程序,但我似乎无法让它工作:

class ThreadTest
{
    static Queue<Thread> threadQueue = new Queue<Thread>();

    static void Main()
    {
        //Create and enqueue threads
        for (int x = 0; x < 2; x++)
        {
            threadQueue.Enqueue(new Thread(() => WriteNumber(x)));
        }

        while(threadQueue.Count != 0)
        {
            Thread temp = threadQueue.Dequeue();
            temp.Start();
        }

        Console.Read();
    }

    static void WriteNumber(int number)
    {
        for (int i = 0; i < 1000; i++)
        {
            Console.Write(number);
        }
    }
}

目标基本上是逐个向队列中添加线程,然后逐个遍历队列并弹出一个线程并执行它。因为我的for循环中有“x&lt; 2”,它应该只生成两个线程 - 一个运行WriteNumber(0),另一个运行WriteNumber(1),这意味着我应该以1000 0和我的屏幕上的1000 1是不同的顺序,具体取决于线程的最终执行方式。

我最终得到的是2000 2。我提出的两个可能的解决方案是:我错过了一些明显的东西,或者将变量x发送到WriteNumber函数正在执行pass-by-reference而不是pass-by-value,所以当线程执行它们使用最新版本的x而不是设置函数时的版本。但是,我的理解是,变量在默认情况下在C#中按值传递,并且只有在参数中包含“ref”时才通过引用传递。

2 个答案:

答案 0 :(得分:18)

您正在lambda表达式中捕获x。在启动线程之前,x的值更改为2。您需要在循环中复制值

for (int x = 0; x < 2; x++)
{
    int copy = x;
    threadQueue.Enqueue(new Thread(() => WriteNumber(copy)));
}

Lambda表达式捕获变量。即使传递给WriteNumber 的值是按值传递,但在线程启动之前根本不会调用它 - 此时x为2。

通过在循环中创建副本,循环的每次迭代都会获得copy变量的独立“实例”,而 在调用WriteNumber时,每个copy变量仍具有x对该次迭代的相同值。

答案 1 :(得分:9)

这是因为在循环结束后访问了x的值,到那时它是2

您需要使用临时变量来防止变量捕获。

for (int x = 0; x < 2; x++)
{
    int tmp = x;
    threadQueue.Enqueue(new Thread(() => WriteNumber(tmp)));
}