Parallel.ForEach 中的竞争条件?

Race condition in 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);
    });
}  

是的。

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

正如其他答案所说,您可以这样做:(此答案的其余部分早于我的更正(感谢 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));
    });
}

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

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

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