How to Create a Thread-Safe Generic List? How to Create a Thread-Safe Generic List? multithreading multithreading

How to Create a Thread-Safe Generic List?


If those are the only functions you are using on List<T> then the easiest way is to write a quick wrapper that synchronizes access with a lock

class MyList<T> {   private List<T> _list = new List<T>();  private object _sync = new object();  public void Add(T value) {    lock (_sync) {      _list.Add(value);    }  }  public bool Find(Predicate<T> predicate) {    lock (_sync) {      return _list.Find(predicate);    }  }  public T FirstOrDefault() {    lock (_sync) {      return _list.FirstOrDefault();    }  }}

I highly recommend the approach of a new type + private lock object. It makes it much more obvious to the next guy who inherits your code what the actual intent was.

Also note that .Net 4.0 introduced a new set of collections specifically aimed at being used from multiple threads. If one of these meets your needs I'd highly recommend using it over rolling your own.

  • ConcurrentStack<T>
  • ConcurrentQueue<T>


If you're using version 4 or greater of the .NET framework you can use the thread-safe collections.

You can replace List<T> with ConcurrentBag<T>:

namespace Playground.Sandbox{    using System.Collections.Concurrent;    using System.Threading.Tasks;    public static class Program    {        public static void Main()        {            var items = new[] { "Foo", "Bar", "Baz" };            var bag = new ConcurrentBag<string>();            Parallel.ForEach(items, bag.Add);        }    }}


To expand on @JaradPar's answer, here is a full implementation with a few extra features, as described in the summary

    /// <summary>/// a thread-safe list with support for:/// 1) negative indexes (read from end).  "myList[-1]" gets the last value/// 2) modification while enumerating: enumerates a copy of the collection./// </summary>/// <typeparam name="TValue"></typeparam>public class ConcurrentList<TValue> : IList<TValue>{    private object _lock = new object();    private List<TValue> _storage = new List<TValue>();    /// <summary>    /// support for negative indexes (read from end).  "myList[-1]" gets the last value    /// </summary>    /// <param name="index"></param>    /// <returns></returns>    public TValue this[int index]    {        get        {            lock (_lock)            {                if (index < 0)                {                    index = this.Count - index;                }                return _storage[index];            }        }        set        {            lock (_lock)            {                if (index < 0)                {                    index = this.Count - index;                }                _storage[index] = value;            }        }    }    public void Sort()    {        lock (_lock)        {            _storage.Sort();        }    }    public int Count    {        get        {            return _storage.Count;        }    }    bool ICollection<TValue>.IsReadOnly    {        get        {            return ((IList<TValue>)_storage).IsReadOnly;        }    }    public void Add(TValue item)    {        lock (_lock)        {            _storage.Add(item);        }    }    public void Clear()    {        lock (_lock)        {            _storage.Clear();        }    }    public bool Contains(TValue item)    {        lock (_lock)        {            return _storage.Contains(item);        }    }    public void CopyTo(TValue[] array, int arrayIndex)    {        lock (_lock)        {            _storage.CopyTo(array, arrayIndex);        }    }    public int IndexOf(TValue item)    {        lock (_lock)        {            return _storage.IndexOf(item);        }    }    public void Insert(int index, TValue item)    {        lock (_lock)        {            _storage.Insert(index, item);        }    }    public bool Remove(TValue item)    {        lock (_lock)        {            return _storage.Remove(item);        }    }    public void RemoveAt(int index)    {        lock (_lock)        {            _storage.RemoveAt(index);        }    }    public IEnumerator<TValue> GetEnumerator()    {        lock (_lock)        {            lock (_lock)            {                return (IEnumerator<TValue>)_storage.ToArray().GetEnumerator();            }        }    }    IEnumerator IEnumerable.GetEnumerator()    {        return GetEnumerator();    }}