并行修改C#对象列表中的属性

时间:2019-06-11 05:54:13

标签: c# parallel-processing task-parallel-library parallel.foreach

我有一个包含对象的列表,并且希望对每个列表项并行运行操作。这些操作之一涉及修改对象的属性。我认为这不应该引起线程安全问题,但是我的单元测试随机失败,因此我担心存在竞争状况。

确切的失败案例是测试将失败,表明列表为空,但是只有当我定期运行我的测试时,如果我以调试模式运行,问题就会消失。我的代码都不应该删除/添加元素,列表是在开始时生成的,然后再也不能直接修改,只能修改元素本身。

是否在C#列表线程安全的类上修改属性?

这是有问题的代码:

List<ExampleObject> localApplications = MethodThatProducesTheList();

Parallel.ForEach(localApplications, localitem =>
{
    if (localitem.BuildLabel.Contains("_Release_"))
    {
        // Delete applications from the old system
        var appToDelete = Path.Combine(AppRootPath, localitem.Name, localitem.BuildLabel);
        DeleteDirectory(appToDelete);
    }
    else
    {
        var st = MethodThatGetsTheState(localitem.BuildLabel);

        localitem.State.Add(st);
    }
});

这是一个更简单的示例:

var object = new { 
    prop = "foo"
};
var list = new[] { object }.ToList();

Parallel.ForEach(list, listItem =>
{
    listItem.prop = "bar";
});

if (list[0].prop != "bar") {
    Assert.Fail()
}

1 个答案:

答案 0 :(得分:1)

好的,因此导致我的问题的原因不是ForEach中的竞争案例,而是计时问题和单例在测试环境中共享的组合。

但是,我最初的问题只是假设在每个列表元素上进行的操作本身都是线程安全的,因此跨线程使用C#列表是否安全?换句话说,在List上使用Parallel.ForEach就像对数组执行类似操作一样,线程安全/不安全。从此处用户的评论看来,答案是

也就是说,就线程安全而言,如果用户未在列表中添加或删除元素,对列表进行排序等,则可以认为列表等同于数组。