c# - 线程启动的竞争条件

标签 c# multithreading race-condition

有人问了类似的问题here ,但答案通常似乎都与 lambda 表示法有关。我在没有 lambda 的情况下得到了类似的结果,所以我想我会要求澄清一下:

假设我有这样的东西:

for (int i = 0; i < 5; i++)
  (new Thread(new ThreadStart(delegate()
    {
      Console.WriteLine("Thread " + i);
    }))).Start();

人们会期望以下输出:

Thread 0
Thread 1
Thread 2
Thread 3
Thread 4

现在我意识到线程没有以任何特定顺序启动,所以让我们假设以上几行可以以任何顺序出现。

但事实并非如此。 相反会发生什么:

Thread 3
Thread 4
Thread 4
Thread 4
Thread 4

或类似的东西,这让我相信它不是传递值 if i,而是传递引用。 (这很奇怪,因为 int 是一种值类型)。

做这样的事情:

for (int i = 0; i < 5; i++)
  (new Thread(new ThreadStart(delegate()
    {
      int j = i;
      Console.WriteLine("Thread " + j);
    }))).Start();

也无济于事,即使我们复制了 i.我假设原因是它没有及时复制 i。

做这样的事情:

for (int i = 0; i < 5; i++)
{
  (new Thread(new ThreadStart(delegate()
    {
      Console.WriteLine("Thread " + i);
    }))).Start();
  Thread.Sleep(50);
}

似乎解决了这个问题,但是这是非常不可取的,因为我们在每次迭代中都浪费了 50 毫秒,更不用说如果计算机负载很重,那么 50 毫秒可能还不够。

这是我当前遇到的具体问题的示例:

Thread t = new Thread(new ThreadStart(delgate()
  {
    threadLogic(param1, param2, param3, param4);
  }));
t.Start();

param1 = param2 = param3 = param4 = null;

与:

void threadLogic(object param1, object param2, object param3, object param4)
{
  // Do some stuff here...
}

我希望 threadLogic() 在它自己的线程中运行,但是上面的代码给出了空引用异常。我假设这是因为在线程有机会启动之前将值设置为 null。

同样,放置一个 Thread.Sleep(100) 是可行的,但从各个方面来看这都是一个糟糕的解决方案。 你们对这种特殊类型的比赛条件有什么建议?

最佳答案

你需要引入一个临时的:

for (int i = 0; i < 5; i++)
{
    int temp = i; // Add this
   (new Thread(new ThreadStart(delegate()
   {
      Console.WriteLine("Thread " + temp);
   }))).Start();
}

问题在于委托(delegate)如何关闭外部变量(i 在你的代码中,temp 在我的代码中)。作用域是错误的(在 for 循环之外),所以当线程开始时,i 已经增加了大部分,如果不是全部的话。


对于你的第二个例子,你需要做同样的事情。只做临时工:

var temp1 = param1;
var temp2 = param2;
var temp3 = param3;
var temp4 = param4;
Thread t = new Thread(new ThreadStart(delgate()
  {
    threadLogic(temp1, temp2, temp3, temp4);
  }));
t.Start();

// This is now safe, since the closure above is over "temp*"
param1 = param2 = param3 = param4 = null; 

关于c# - 线程启动的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4939682/

相关文章:

go - 即使使用互斥锁,打印结构字段时也会出现竞争条件

c# - 使用 Fortran DLL 进行 NUnit 测试

c++ - 是否可以(从 C++ 中)将具有不同值的 "same"常量公开给多个 Lua 协程?

linux - 如果主线程完成,C++ 程序在什么情况下会继续?

c++ - Clang ThreadSanitizer : unlock of an unlocked mutex,和一个原子正在创建数据争用

c++ - 阻塞队列实现 : Where's the race condition?

C++:线程竞争条件是否会破坏每字节级别的静态/全局整数值?

c# - SQL Server 应用程序 - 将数据库重置为原始状态

c# - 在 C# 中将参数传递给变量的更短方法?

c# - Entity Framework 6 迁移是否可以包含围绕脚本的事务?