我有一个ConcurrentBag集合,对于其中的每个项目,我都会做一些工作。

我知道带有ConcurrentBag的Parallel.ForEach是线程安全的,但我从未以这种方式进行并行处理。

我的代码看起来像这样

public void Work(IList<MyModel> data)
{
   var tasks = new ConcurrentBag<Task>();
   var safeData = new ConcurrentBag<MyModel>(data);
   foreach (var item in safeData )
   {
      var task = Task.Factory.StartNew(() => SomeTask(item));
      tasks.Add(task);
   }
   Task.WaitAll(tasks.ToArray());
}

那么,这段代码是线程安全的吗?

谢谢

编辑:
也许这个问题可能是:“item”是线程安全的还是可以在两次迭代之间更改其值?

编辑2:
如果此代码可能属于problem,我将引用a。

编辑3:
在此question中,“理智的元子”直接使用循环变量时会遇到问题。我认为可以使用ConcurrentBag纠正此问题,但是在某些答案中,请告诉我我根本不需要ConcurrentBag。所以:

一个好主意是直接使用循环变量吗?

建议何时将值复制到另一个变量?

直接与ConcurrentBag中的循环变量一起使用是否安全?

最佳答案

除了现有的答案:

问题不在于多线程或并发。关于closures

  • 如果您了解发生了什么,可以直接使用循环变量。
  • 如果是foreach,则取决于您的编译器版本。如果使用旧版本编译代码,则会导致问题,如that very question中所述。如果使用for循环,则应始终复制循环变量。有关更多详细信息,请参见Jon's answer中的链接。
  • 如前所述,使用ConcurrentBag不会影响结果。
    如果您使用的编译器版本比4.0.30319.1更旧(对于MS编译器),则关闭循环变量是安全的。 More info about compiler versions

  • 同样,如对该问题的评论中所述,您可以使用静态分析工具来突出显示这种情况。

    10-04 14:31