Параллельное изменение свойств в списке объектов C # - PullRequest
0 голосов
/ 11 июня 2019

У меня есть список, содержащий объекты, и я хочу параллельно выполнять операции с каждым элементом списка.Одна из этих операций включает изменение свойства объекта.Я думал, что это не должно вызывать проблем с безопасностью потоков, но мой модульный тест проваливается случайно, поэтому я волнуюсь, что есть состояние гонки.

Точный случай сбоя заключается в том, что тест завершится неудачно, сообщив, что список пуст, но только если я регулярно запускаю свой тест, если я запускаю в режиме отладки, проблема исчезает.Ни один из моего кода не должен удалять / добавлять элементы, список генерируется в начале, а затем никогда не изменяется напрямую, изменяются только сами элементы.

Безопасно ли изменение свойств классов в списке 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 Ответ

1 голос
/ 11 июня 2019

Хорошо, поэтому проблема, вызвавшая мою проблему, была не в гонке ForEach, а в сочетании с проблемой синхронизации и синглтоном, совместно используемым в тестовой среде.

Тем не менее, мой первоначальный вопрос состоял в том, просто ли безопасно использовать список C # в потоках, предполагая, что операции, выполняемые с каждым элементом списка, сами по себе являются потокобезопасными. Другими словами, использует Parallel.ForEach для List так же, как потокобезопасный / небезопасный, как делает аналогичную операцию над массивом. Из комментариев пользователей здесь, похоже, ответ да .

А именно, что с точки зрения безопасности потока список можно считать эквивалентным массиву, если пользователь не добавляет или не удаляет элементы из списка, не сортирует список и т. Д.

...