【问题标题】:Passing data to a thread using Lambda expressions使用 Lambda 表达式将数据传递给线程
【发布时间】:2013-01-09 04:51:40
【问题描述】:
for (int i = 0; i < 10; i++)
  new Thread (() => Console.Write (i)).Start();

正如预期的那样,上述代码的输出是不确定的,因为 i 变量在循环的整个生命周期中都指向同一个内存位置。因此,每个线程都会在一个变量上调用 Console.Write,该变量的值可能会在运行时发生变化

然而,

for (int i = 0; i < 10; i++)
{
  int temp = i;
  new Thread (() => Console.Write (temp)).Start();
}

也给出了不确定的输出!我认为变量 temp 是每个循环迭代的本地变量。因此,每个线程捕获了不同的内存位置,应该存在np问题。

【问题讨论】:

  • 输出的不确定性是什么?
  • 第二个版本应该可以工作 - Eric Lippert 在这里写了关于循环变量闭包的博客:blogs.msdn.com/b/ericlippert/archive/2009/11/12/…
  • 它不应该是“确定性的”,因为“调度的线程的顺序总是相同的”。也许这就是问题的意思?
  • 你的意思是你的输出应该打印为 123...9?
  • @JeffWatkins int 是一个原语,但是因为它是在闭包中捕获的,所以它实际上存储在一个堆对象中。第一个示例在堆上创建一个闭包对象,所有 10 个线程都使用该对象。第二个示例在堆上创建了 10 个不同的闭包对象,每个线程一个。按照 Paolo 指向 Eric Lippert 博客的链接,或阅读 Honza Brestan 的回答进行简短讨论。

标签: c# multithreading


【解决方案1】:

您的程序应该有 10 个 lambdas,每个 lambdas 将 0 到 9 中的一个数字写入控制台。但是,不能保证线程会按顺序执行。

【讨论】:

  • OP 的代码中没有换行符,所以所有数字都在唯一的一行上。
  • @AgentFire 啊,我明白了。我看到只有“Write”的“WriteLine”。我已经编辑了一些答案。
  • Console.Write() 线程安全的,因为写入它的整个字符串将永远将它们的字符交错。
  • @MatthewWatson 你是对的。我描述的输出是基于我最近工作的经验,但这一定是由于在不同线程上多次调用控制台造成的。我到办公室去看看。
【解决方案2】:

也给出了不确定的输出!

不,不是。我检查了你的第一个代码(有重复的数字)和第二个(没有)十次。

所以一切正常。就像它应该的那样。

【讨论】:

    【解决方案3】:

    second 代码 sn-p 应该是确定性的,因为每个线程最终都会写入其temp,并且它们的所有时间都会不同。

    但是,它不保证线程将按其创建顺序安排执行。您会看到所有可能的临时时间,但不一定按升序排列。

    【讨论】:

      【解决方案4】:

      这是证明 OP 是正确的并且他的两段代码都不正确的证据。

      还有一个有证据的解决方案。

      但需要注意的是,'non-deterministic' 意味着线程接收到错误的参数订单将从不保证。

      下面的代码检查第二段 OP 代码并证明它按预期工作..

      我正在存储对(线程标识,参数),然后将其打印出来与线程输出进行比较,以证明对没有改变。我还添加了几百毫秒的随机睡眠,因此 for 索引在这些时候应该会明显改变。

              Dictionary<int, int> hash = new Dictionary<int, int>();
              Random r = new Random(DateTime.Now.Millisecond);
              for (int i = 0; i < 10; i++)
              {
                  int temp = i;
                  var th = new Thread(() =>
                  {
                      Thread.Sleep(r.Next(9) * 100);
                      Console.WriteLine("{0} {1}", 
                          Thread.CurrentThread.GetHashCode(), temp);
                  });
      
                  hash.Add(th.GetHashCode(), temp);
      
                  th.Start();
              }
      
              Thread.Sleep(1000);
              Console.WriteLine();
      
              foreach (var kvp in hash)
                  Console.WriteLine("{0} {1}", kvp.Key, kvp.Value);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多