- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
请检查下面的代码示例:
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
,您将看到不同的输出。
通常的解决方法是:
捕获“复制”变量而不是 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/
我在我的应用程序中使用 Windows ThreadPools,每次调用 CreateThreadPoolWork() 时都会遇到 136 字节的内存泄漏,如通过 UMDH 所见: + 1257728
摘自对我之前一个问题的回答( Task.Factory.StartNew starts with a great delay despite having available threads in t
这有什么区别?请引用选项1和选项2。因为我遇到了麻烦,因为它们好像是一样的。它们运行正确 Thread ThreadPoolExecutor executor = (ThreadPoolExecuto
Windows Phone 8 SDK 文档没有描述 Windows.System.Threading.ThreadPool 之间的区别。和 System.Threading.ThreadPool .
我无法通过JSP使用Elasticsearch Java API。在下面,我试图解释我所做的事情。 :| 我已经按照 flex 指令在系统上安装了elasticseach 2.3.3,并在命令提示符下
我试图在 Thread 的帮助下找出控制台应用程序中运行的线程数: new Thread(() => { while (true) {
我们对来自 Android 应用程序的所有网络流量使用 Retrofit/OkHttp3。到目前为止,一切似乎都很顺利。 但是,我们现在偶尔会遇到我们的应用程序/进程用完文件句柄的情况。 Androi
我们应该为长时间运行的线程使用线程池还是启动我们自己的线程?有什么设计模式吗? 最佳答案 不幸的是,这取决于。没有硬性规定说您应该始终使用线程池。 线程池提供两个主要功能: 线程的委托(delegat
我只是实现了一个线程池,如这里所述 Allen Bauer on thread pools 非常简单的实现,可以正常工作,但是我的应用程序不再关闭。似乎有两个工作线程(和另一个线程,我想是排队线程)卡
我有以下代码: static void Main(string[] args) { Console.Write("Press ENTER to start..."); Console.
我在下面编写了一个示例程序。 class Program { static int x = 2; static void Main(string[] args)
我试图了解Parralel.For和ThreadPool.QueueUserWorkItem之间的区别。 硬件和软件: 英特尔i5(四核) Windows 7 64位教授 DotNet 4.5 案例1
当用户单击按钮时,我使用ThreadPool.QueueUserWorkItem生成了一个启动长时间运行的线程的线程。我想在线程完成时使按钮可见,以便用户可以单击它。 ThreadPool中是否有已完
我想要一个类似的功能: public static V callAsyncAndWait(Func func) { ThreadPool.QueueUserWorkItem(obj =>
我正在尝试编写一个 Java 多线程程序,对作为文件给出的 2 个矩阵执行乘法,并使用有限的线程总数。 例如,如果我将线程数设置为 16,我希望我的线程池能够重用这 16 个线程,直到所有任务完成。
我有一个 C# 控制台应用程序,其中有一个线程池。在线程池中会有一个类执行一个连续的方法(直到它运行了一段时间或者知道什么时候停止)。该方法连接到 HttpWebResponse 流并继续读取它。 问
我正在使用 Reflector 仔细阅读 .Net ThreadPool 的一些源代码,当它显示以下内容时: private static bool QueueUserWorkItemHelper(W
每当用户扫描条形码时,我都会触发一个线程。 大多数时候它是一个相当短的运行线程。但有时可能需要很长时间(等待调用 GUI 线程)。 我读到过,为此使用 ThreadPool 可能是个好主意,而不是为每
我有一个场景,我试图通过在可能的情况下在用户实际需要之前预取结果的一些子元素来转变为响应速度更快的 UI。我不清楚如何最好地处理线程,所以我希望有人可以提供一些建议。 场景 有一个搜索表单(.NET
我需要对事件进行排队并并行执行它们。 我的 C# 代码在阻塞集合中对事件进行排队,并使用 ThreadPool 在工作线程上执行每个事件。但是,如果事件以 2000 事件/秒或更高的速率排队,则会错过
我是一名优秀的程序员,十分优秀!