【问题标题】:Simple Threading in C# [duplicate]C#中的简单线程[重复]
【发布时间】:2012-06-19 21:32:15
【问题描述】:

可能重复:
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

我最终得到的是 2000 个 2。我想出的两个可能的解决方案是:我错过了一些非常明显的事情,或者将变量 x 发送到 WriteNumber 函数正在执行传递引用而不是传递值,所以当线程执行他们使用最新版本的 x 而不是设置函数时的版本。但是,据我了解,变量在 C# 中默认按值传递,并且只有在参数中包含 'ref' 时才通过引用传递。

【问题讨论】:

  • 线程队列肯定是一个不寻常的想法。
  • 这不是一个奇怪的想法,这就是线程池在内部所做的。所以使用线程池。
  • 线程池通常有一个任务类实例的队列,如果它们可以跟踪跟踪,则有一个固定的线程列表,可以使任务出列并执行任务。列表/队列中的微观管理线程通常会导致灾难。我已经在 SO 上看到了一些尝试——大量代码试图轮询列表中的线程是否“完成”,释放它们并创建新的线程来填充数组中的漏洞。真可怕……

标签: c# multithreading


【解决方案1】:

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

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

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

通过在循环中制作副本,循环的每次迭代都会获得自己单独的 copy 变量“实例”,并且 不会改变值...所以由在调用WriteNumber 时,每个copy 变量仍然具有与x 相同的值。

【讨论】:

  • 令人着迷,谢谢!看来我对 lambda 表达式还有很多研究要做!
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-10
    • 2022-01-10
    • 2011-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 2013-11-22
    相关资源
    最近更新 更多