gpt4 book ai didi

c# - ThreadPool.QueueUserWorkItem 的意外行为

转载 作者:太空狗 更新时间:2023-10-29 21:14:54 25 4
gpt4 key购买 nike

请检查下面的代码示例:

public class Sample
{
public int counter { get; set; }
public string ID;
public void RunCount()
{
for (int i = 0; i < counter; i++)
{
Thread.Sleep(1000);

Console.WriteLine(this.ID + " : " + i.ToString());
}
}
}

class Test
{
static void Main()
{
Sample[] arrSample = new Sample[4];

for (int i = 0; i < arrSample.Length; i++)
{
arrSample[i] = new Sample();
arrSample[i].ID = "Sample-" + i.ToString();
arrSample[i].counter = 10;
}

foreach (Sample s in arrSample)
{
ThreadPool.QueueUserWorkItem(callback => s.RunCount());
}

Console.ReadKey();
}

}

此示例的预期输出应类似于:

Sample-0 : 0 
Sample-1 : 0
Sample-2 : 0
Sample-3 : 0
Sample-0 : 1
Sample-1 : 1
Sample-2 : 1
Sample-3 : 1
.
.
.

但是,当您运行这段代码时,它会显示如下内容:

Sample-3 : 0 
Sample-3 : 0
Sample-3 : 0
Sample-3 : 1
Sample-3 : 1
Sample-3 : 0
Sample-3 : 2
Sample-3 : 2
Sample-3 : 1
Sample-3 : 1
.
.
.

我可以理解线程执行的顺序可能不同,因此计数不会以循环方式增加。但是,我不明白为什么所有的 ID 都显示为 Sample-3,而执行显然是相互独立的。

不同的对象是否被不同的线程使用?

最佳答案

这是旧的修改闭包问题。你可能想看看:Threadpools - possible thread execution order problem对于类似的问题,Eric Lippert 的博客文章 Closing over the loop variable considered harmful了解问题。

本质上,您获得的 lambda 表达式捕获的是 变量 s 而不是变量的 value声明了 lambda。因此,对变量值所做的后续更改 对委托(delegate)可见。 RunCount 方法将在其上运行的 Sample 实例将取决于变量 s 引用的实例(其值)在委托(delegate)实际执行的时候

此外,由于委托(delegate)(编译器实际上重用了同一个委托(delegate)实例)是异步执行的,所以不能保证每次执行时这些值是什么。您目前看到的是 foreach 循环在主线程上完成 before 任何委托(delegate)调用(可以预料 - 在主线程上安排任务需要时间线程池)。因此,所有 工作项最终都会使用循环变量的“最终”值。但这不能以任何方式保证;尝试在循环中插入一个合理持续时间的 Thread.Sleep,您将看到不同的输出。


通常的解决方法是:

  1. 在循环体内引入另一个变量。
  2. 将该变量分配给循环变量的当前值。
  3. 捕获“复制”变量而不是 lambda 中的循环变量。

    foreach (Sample s in arrSample)
    {
    Sample sCopy = s;
    ThreadPool.QueueUserWorkItem(callback => sCopy.RunCount());
    }

现在每个工作项“拥有”循环变量的特定值。


在这种情况下,另一种选择是通过不捕获任何东西来完全避免问题:

ThreadPool.QueueUserWorkItem(obj => ((Sample)obj).RunCount(), s);

关于c# - ThreadPool.QueueUserWorkItem 的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4744630/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com