Parallel.ForEach中的竞争条件?

时间:2016-03-21 02:47:37

标签: c# race-condition parallel.foreach

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

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);
    });
}  

2 个答案:

答案 0 :(得分:11)

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

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));

答案 1 :(得分:1)

(编辑删除错误且分散注意力的信息)

正如另一个答案所说,你可以这样做:(这个答案的剩余部分早于我的更正(感谢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));
    });
}

显然没有覆盖物体或记忆的风险。