3

I have C# .NET 4 code which is adding to a List<string> inside a Parallel.For. I can't find a definite answer to if this is thread-safe or not. If it is unsafe what are the alternatives?

    static List<int> Calculate(List<string[]> numbers)
    {
           List<int> sums = new List<int>();

         
            Parallel.ForEach(numbers,
            (nums) =>
            {
                int sum = 0;
                for (int i = 0; i < nums.Length; i++)
                     sum += Convert.ToInt32( nums[i]);

                // is this thread safe or not???
                sums.Add(sum);
            });

            sums.Sort();
            return sums;
    }
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
user2425056
  • 327
  • 2
  • 4
  • 14
  • 6
    You can find a definite answer by **reading the documentation**, specifically the section labeled "Thread Safety". http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx – Eric Lippert Jul 10 '13 at 15:56
  • Does this answer your question? [Thread-safe List property](https://stackoverflow.com/questions/5874317/thread-safe-listt-property) – Michael Freidgeim Apr 17 '23 at 06:33

3 Answers3

12

No, it's not thread-safe. You might be looking for the ConcurrentBag<T> class, a thread-safe unordered collection. Some more info and other thread-safe collections are available at MSDN's Thread-Safe Collections documentation. E.g.

static List<int> Calculate(List<string[]> numbers)
{
       var sums = new ConcurrentBag<int>();


        Parallel.ForEach(numbers,
        (nums) =>
        {
            int sum = 0;
            for (int i = 0; i < nums.Length; i++)
                 sum += Convert.ToInt32( nums[i]);

            sums.Add(sum);
        });

        var sorted = sums.OrderBy(x => x).ToList();
        return sorted;
}
Tim S.
  • 55,448
  • 7
  • 96
  • 122
  • 1
    I removed both my comment and my answer, because I thought `sums` and `nums` is the same list. That is not the case, making all my argumentation moot. You are of course correct that the concurrent bag helps here. – Daniel Hilgarth Jul 10 '13 at 16:10
4

You can avoid thread-safety issues (and gain on performance) by converting your method into a PLINQ operation:

static List<int> Calculate(List<string[]> numbers)
{
    return numbers.AsParallel()
                  .Select(nums => nums.Sum(Convert.ToInt32))
                  .OrderBy(i => i)
                  .ToList();
}
Douglas
  • 53,759
  • 13
  • 140
  • 188
3

No it's not.

A List can support multiple readers concurrently, as long as the collection is not modified. Enumerating through a collection is intrinsically not a thread-safe procedure. In the rare case where an enumeration contends with one or more write accesses, the only way to ensure thread safety is to lock the collection during the entire enumeration. To allow the collection to be accessed by multiple threads for reading and writing, you must implement your own synchronization.

From MSDN

ken2k
  • 48,145
  • 10
  • 116
  • 176