【问题标题】:Race condition in Parallel.ForEach?Parallel.ForEach 中的竞争条件?
【发布时间】:2016-03-21 02:47:37
【问题描述】:

以下代码中是否存在可能的竞争条件?

public void Process(List<SomeObject> list)
{
    SomeDataOutput objData=null;
    ConcurrentBag<SomeDataOutput> cbOutput = new ConcurrentBag<SomeDataOutput>();
    ParallelOptions po = new ParallelOptions(){MaxDegreeOfParallelism=4};
    Parallel.ForEach(list, po, (objInput) =>
    {
        objData = GetOutputData(objInput);//THIS LINE IS THE ONE I AM UNSURE OF. CAN objData GET OVERWRITTEN BY MULTIPLE PARALLEL THREADS?
        cbOutput.Add(objData);
    });
}  

【问题讨论】:

  • 这将取决于您如何实现GetOutputData,因为这是分配或重用现有对象的方法。 objDataForEach 之外声明这一事实本身并不意味着一个线程存在读取另一个线程对象的风险。
  • @PaulHicks:除了否认这是一个问题之外,您已经非常准确地描述了这个问题。 objData 在 lambda 之外声明的事实意味着它是一个捕获,并且 lambda 的所有实例将共享一个变量。所以是的,肯定存在一个线程读取另一个线程对象的风险。

标签: c# race-condition parallel.foreach


【解决方案1】:

是的,可能存在竞争条件。两个线程可能将循环体中的语句交错如下:

Thread #1                             Thread #2
==================================    ==================================
objData = GetOutputData(objInput);
                                      objData = GetOutputData(objInput);
cbOutput.Add(objData);
                                      cbOutput.Add(objData);

因为objData是在循环外声明的,所以两个线程共享同一个变量。结果,线程#2 覆盖了线程#1 设置的objData 引用,线程#2 的objData 被两次添加到cbOutput

为防止objData被多个线程共享,将其设为局部变量:

SomeDataOutput objData = GetOutputData(objInput);
cbOutput.Add(objData);

或者你可以完全摆脱这个变量:

cbOutput.Add(GetOutputData(objInput));

【讨论】:

  • 谢谢迈克尔。这也是我的确切疑问。只是为了理解-如果我将其更改为 Parallel.ForEach(list,po,(objInput) => {cbOutput.Add(GetOutputData(objInput))});会有什么不同吗?
  • 是的,这也解决了问题。相当于我的第二个建议。
  • 谢谢 - 刚刚看到...非常感谢。
【解决方案2】:

是的。

(已编辑以删除不正确和分散注意力的信息)

正如另一个答案所说,你可以这样做:(这个答案的其余部分早于我的更正(感谢 Ben Voight)。

public void Process(List<SomeObject> list)
{
    ConcurrentBag<SomeDataOutput> cbOutput = new ConcurrentBag<SomeDataOutput>();
    ParallelOptions po = new ParallelOptions(){MaxDegreeOfParallelism=4};
    Parallel.ForEach(list, po, (objInput) =>
    {
        cbOutput.Add(GetOutputData(objInput));
    });
}

这显然没有覆盖对象或内存的风险。

【讨论】:

  • 不,不完全等价。
  • 是的,它又开始让我感到困惑了。我回答说存在竞争条件,然后我对其进行了测试,但无法创建它,然后我写了这个答案。看起来我需要更努力地重现它:)
  • 很遗憾,测试无法证明不存在竞争条件。
  • 感谢 Ben,Paul - 非常有用的讨论。
猜你喜欢
  • 1970-01-01
  • 2016-03-07
  • 2011-07-17
  • 2013-02-27
  • 2021-04-16
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
相关资源
最近更新 更多