List.Add() thread safety

后端 未结 9 2109
庸人自扰
庸人自扰 2020-11-29 07:57

I understand that in general a List is not thread safe, however is there anything wrong with simply adding items into a list if the threads never perform any other operation

相关标签:
9条回答
  • 2020-11-29 08:16

    If you want to use List.add from multiple threads and do not care about the ordering, then you probably do not need the indexing ability of a List anyway, and should use some of the available concurrent collections instead.

    If you ignore this advice and only do add, you could make add thread safe but in unpredictable order like this:

    private Object someListLock = new Object(); // only once
    
    ...
    
    lock (someListLock)
    {
        someList.Add(item);
    }
    

    If you accept this unpredictable ordering, chances are that you as mentioned earlier do not need a collection that can do indexing as in someList[i].

    0 讨论(0)
  • 2020-11-29 08:16

    Even adding elements on different threads is not thread safe.

    In C# 4.0 there are concurrent collections (see http://jiezhu0815.blogspot.com/2010/08/c-40-feature-1-concurrent-collections.html).

    0 讨论(0)
  • 2020-11-29 08:18

    This would cause problems, as the List is built over an array and is not thread safe you might get index out of bounds exception or some values overriding other values, depending on where the threads are. Basically, don't do it.

    There are multiple potential problem... Just don't. If you need a thread safe collection, either use a lock or one of the System.Collections.Concurrent collections.

    0 讨论(0)
  • 2020-11-29 08:20

    You current approach is not thread-safe - I would suggest avoiding this altogether - since you basically do a data transformation PLINQ might be a better approach ( I know this is a simplified example but in the end you are projecting each transaction into another "state" object).

    List<object> list = transactions.AsParallel()
                                    .Select( tran => new object())
                                    .ToList();
    
    0 讨论(0)
  • 2020-11-29 08:23

    As others already said, you can use concurrent collections from the System.Collections.Concurrent namespace. If you can use one of those, this is preferred.

    But if you really want a list which is just synchronized, you could look at the SynchronizedCollection<T>-Class in System.Collections.Generic.

    Note that you had to include the System.ServiceModel assembly, which is also the reason why I don't like it so much. But sometimes I use it.

    0 讨论(0)
  • Is there anything wrong with simply adding items into a list if the threads never perform any other operations on the list?

    Short answer: yes.

    Long answer: run the program below.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    
    class Program
    {
        readonly List<int> l = new List<int>();
        const int amount = 1000;
        int toFinish = amount;
        readonly AutoResetEvent are = new AutoResetEvent(false);
    
        static void Main()
        {
            new Program().Run();
        }
    
        void Run()
        {
            for (int i = 0; i < amount; i++)
                new Thread(AddTol).Start(i);
    
            are.WaitOne();
    
            if (l.Count != amount ||
                l.Distinct().Count() != amount ||
                l.Min() < 0 ||
                l.Max() >= amount)
                throw new Exception("omg corrupted data");
    
            Console.WriteLine("All good");
            Console.ReadKey();
        }
    
        void AddTol(object o)
        {
            // uncomment to fix
            // lock (l) 
            l.Add((int)o);
    
            int i = Interlocked.Decrement(ref toFinish);
    
            if (i == 0)
                are.Set();
        }
    }
    
    0 讨论(0)
提交回复
热议问题