- 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/
我正在尝试使用下面的代码来触发多个线程来使用 HttpWebRequest。我在所有可能的请求中做了一个foreach(每个请求都有不同的数据),但是当我将请求传递给消费方法时,它似乎总是只接收列表中
也许这个问题不会出现在这里.... 我正在使用 ThreadPool.QueueUserWorkItem 写入文件夹/文件,我的问题是当它尝试写入时我遇到了 UnauthorizedAccessExc
我在 .net 4.0 中使用 C# ThreadPool.QueueUserWorkItem 线程安全吗? 例子: Parallel.ForEach(commands, commandModel =
这可能是由于缺乏对引擎盖下发生的事情的理解,或者仅仅是缺乏对一般线程的理解。当用户登录时,我需要运行一些调用 Web 服务的任务来更新我系统中的数据。由于服务可能会花费大量时间,因此我将整个过程进行了
我正在为网站开发多线程抓取工具,根据另一个问题,我决定将 ThreadPool 与 QueueUserWorkItem() 一起使用。 如何连续对工作项进行排队,而不是一次将它们全部排队?我需要排队
为什么我会收到此错误。我的变量从请求中获取名称,我也尝试了“data.qext”,但 visual studio 给我错误。 我的 WebsiteRoot/uploads/files/test.pdf
.NET 4.5 和 VS2012 是我的目标 在我的 C# 中,我有很多这样的旧代码: var stuff; ThreadPool.QueueUserWorkItem(() => {
我刚刚注意到通过 ThreadPool.QueueUserWorkItem 排队的回调顺序不是确定性的,它肯定不是回调传入的顺序。 这可以用下面的简单程序来验证: private static
我有一个 ConcurrentQueue,其中填充了任意数量的对象,我想在单独的线程中处理这些对象。 如何等待所有排队的工作项目完成?我看到的示例使用固定的 ManualResetEvents 数组,
我实现了一个日志记录方法如下: ThreadPool.QueueUserWorkItem((state) => { lock (appendLock) { using (Str
我正在使用 C# 2.0 并且想在 ThreadPool.QueueUserWorkItem 的帮助下调用带有几个参数的方法,所以我尝试如下: ThreadPool.QueueUserWorkItem
我有一个 MonoTouch 应用程序,它使用线程池来管理后台线程的数量。如果我让 ThreadPool 产生一个线程并在该线程内,它会触发一个异步 Web 请求,那么该 Web 请求是否会产生第二个
我正在尝试以这种方式使用该方法: public void Method() { ThreadPool.QueueUserWorkItem(() => {
我有一个控制台应用程序可以将定制的电子邮件(带附件)发送给不同的收件人,我想同时发送它们。我需要创建单独的 SmtpClients 来实现这一点,因此我使用 QueueUserWorkItem 来创建
请检查下面的代码示例: public class Sample { public int counter { get; set; } public string ID; pub
每当我的 ThreadPool 中的线程抛出异常时,我的代码似乎卡在线程函数内的 catch block 中。如何将异常返回到主线程? 最佳答案 最佳实践是您的后台线程不应抛出异常。让他们自己处理异常
我创建了一个通讯系统,允许我指定哪些成员应该接收通讯。然后,我遍历满足条件的成员列表,并为每个成员生成个性化消息并异步向他们发送电子邮件。 当我发送电子邮件时,我正在使用 ThreadPool.Que
我将最大线程设置为 10。然后我使用 ThreadPool.QueueUserWorkItem 添加了 22000 个任务。很可能运行程序后22000的任务并没有全部完成。有多少任务可以排队等待可用线
如果我使用 QueueUserWorkItem 将作业添加到线程池...我如何在所有作业完成之前阻止我的程序继续运行? 我知道我可以添加一些逻辑来阻止应用程序运行,直到所有作业都完成,但我想知道是否有
我现在正在使用以下代码添加排队的线程。我不喜欢它。我的同事也不会,因为他们不太了解 C#。当然,我想要的只是将要在新线程中执行的方法排队。 private static void doStuff(st
我是一名优秀的程序员,十分优秀!