gpt4 book ai didi

c# - 线程池 - 可能的线程执行顺序问题

转载 作者:行者123 更新时间:2023-12-02 11:02:27 24 4
gpt4 key购买 nike

我一直在学习如何使用线程池,但我不确定池中的每个线程是否都正确执行,并且我怀疑有些线程被执行多次。我已将代码削减到最低限度,并一直在使用 Debug.WriteLine 来尝试弄清楚发生了什么,但这会产生一些奇怪的结果。

我的代码如下(基于( WaitAll for multiple handles on a STA thread is not supported )的代码:

public void ThreadCheck()
{
string[] files;
classImport Import;
CountdownEvent done = new CountdownEvent(1);
ManualResetEvent[] doneEvents = new ManualResetEvent[10];

try
{
files = Directory.GetFiles(importDirectory, "*.ZIP");

for (int j = 0; j < doneEvents.Length; j++)
{
done.AddCount();
Import = new classImport(j, files[j], workingDirectory + @"\" + j.ToString(), doneEvents[j]);
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
Import.ThreadPoolCallBack(state);
Debug.WriteLine("Thread " + j.ToString() + " started");
}
finally
{
done.Signal();
}
}, j);

}

done.Signal();
done.Wait();
}
catch (Exception ex)
{
Debug.WriteLine("Error in ThreadCheck():\n" + ex.ToString());
}
}

classImport.ThreadPoolCallBack 目前实际上没有执行任何操作。

如果我手动单步执行代码,我会得到:

线程 1 已启动线程 2 已启动....一路到....线程 10 已启动

但是,如果我手动运行它,输出窗口将填充“线程 10 已启动”

我的问题是:我使用线程池的代码是否有问题,或者 Debug.WriteLine 的结果是否被多个线程混淆了?

最佳答案

问题在于您在 lambda 表达式中使用了循环变量 (j)。

为什么这是一个问题的细节相当冗长 - 请参阅 Eric Lippert's blog post了解详细信息(另请阅读 part 2 )。

幸运的是,解决方法很简单:只需在循环内创建一个新的局部变量,并在 lambda 表达式中使用它:

for (int j = 0; j < doneEvents.Length; j++)
{
int localCopyOfJ = j;

... use localCopyOfJ within the lambda ...
}

对于循环体的其余部分,只使用 j 就可以了 - 只有当它被 lambda 表达式或匿名方法捕获时,它才会成为问题。

这是一个困扰很多人的常见问题 - C# 团队已考虑更改 foreach 循环的行为(其中确实看起来像您已经在每次迭代中声明了一个单独的变量),但这会导致有趣的兼容性问题。 (例如,您可以编写运行良好的 C# 5 代码,而使用 C# 4 它可能可以编译正常,但实际上会被破坏。)

关于c# - 线程池 - 可能的线程执行顺序问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4469554/

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