List.Add() thread safety

后端 未结 9 2110
庸人自扰
庸人自扰 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:34

    It's not an unreasonable thing to ask. There are cases where methods which can cause thread-safety issues in combination with other methods are safe if they are the only method called.

    However, this clearly isn't a case of it, when you consider the code shown in reflector:

    public void Add(T item)
    {
        if (this._size == this._items.Length)
        {
            this.EnsureCapacity(this._size + 1);
        }
        this._items[this._size++] = item;
        this._version++;
    }
    

    Even if EnsureCapacity was in itself threadsafe (and it most certainly is not), the above code is clearly not going to be threadsafe, considering the possibility of simultaneous calls to the increment operator causing mis-writes.

    Either lock, use ConcurrentList, or perhaps use a lock-free queue as the place multiple threads write to, and the read from it - either directly or by filling a list with it - after they have done their work (I'm assuming that multiple simultaneous writes followed by single-threaded reading is your pattern here, judging from your question, as otherwise I can't see how the condition where Add is the only method called could be of any use).

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

    Behind the scenes lots of things happen, including reallocating buffers and copying elements. That code will cause danger. Very simply, there are no atomic operations when adding to a list, at the least the "Length" property needs to be updates, and item needs to be put in at the right location, and (if there's a separate variable) the index needs to be updated. Multiple threads can trample over each other. And if a grow is required then there is lots more going on. If something is writing to a list nothing else should be reading or writing to it.

    In .NET 4.0 we have concurrent collections, which are handily threadsafe and don't require locks.

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

    I solved my problem using ConcurrentBag<T> instead of List<T> like this:

    ConcurrentBag<object> list = new ConcurrentBag<object>();
    Parallel.ForEach(transactions, tran =>
    {
        list.Add(new object());
    });
    
    0 讨论(0)
提交回复
热议问题