Потокобезопасные списки C#
У меня вопрос, есть ли какие нибудь потокобезопасные списки?
Я понимаю что можно использовать lock, но интересует способ без использования блокировки коллекции.
Просто в теории допустим, что есть около 20 потоков которые работают с 1 коллекцией и как можно добавлять и изымать оттуда "информацию".
Ответы (1 шт):
Так как комментариев накидали много, а прямого дубликата данного вопроса я не нашел, оформлю ответом.
Потокобезопасные коллекции
Пространство имён System.Collections.Concurrent (документация) содержит все стандартные потокобезопасные коллекции. Их поведение и методы отличаются от обычных аналогов, поэтому стоит изучить, как с ними правильно работать. Половина потокобезопасных коллекций строится на интерфейсе IProducerConsumerCollection<T>, он то и добавляет что-то общее между этими коллекциями. Остальные имеют более специфическое назначение.
Почитать про потокобезопасные коллекции можно здесь. Можно посмотреть даже видео.
ConcurrentList<T>
Так же стоит отметить, что в .NET отсутствует коллекция ConcurrentList<T>, есть подробный ответ на этот вопрос.
Вот пример реализации самого простого потокобезопасного списка на базе ReaderWriterLockSlim, который я когда-то написал для другого ответа. Можно считать это болванкой для своего собственного решения.
ConcurrentList.cs
public class ConcurrentList<T> : IEnumerable<T>, ICollection<T>
{
private readonly List<T> _list;
private readonly ReaderWriterLockSlim _lock;
public int Count
{
get
{
try
{
_lock.EnterReadLock();
return _list.Count;
}
finally
{
_lock.ExitReadLock();
}
}
}
public bool IsReadOnly => false;
public ConcurrentList() : this(null) { }
public ConcurrentList(IEnumerable<T> items)
{
_list = items is null ? new List<T>() : new List<T>(items);
_lock = new ReaderWriterLockSlim();
}
public void Add(T item)
{
try
{
_lock.EnterWriteLock();
_list.Add(item);
}
finally
{
_lock.ExitWriteLock();
}
}
public void Clear()
{
try
{
_lock.EnterWriteLock();
_list.Clear();
}
finally
{
_lock.ExitWriteLock();
}
}
public bool Contains(T item)
{
try
{
_lock.EnterReadLock();
return _list.Contains(item);
}
finally
{
_lock.ExitReadLock();
}
}
public void CopyTo(T[] array, int arrayIndex)
{
try
{
_lock.EnterReadLock();
_list.CopyTo(array, arrayIndex);
}
finally
{
_lock.ExitReadLock();
}
}
public bool Remove(T item)
{
try
{
_lock.EnterWriteLock();
return _list.Remove(item);
}
finally
{
_lock.ExitWriteLock();
}
}
private IEnumerable<T> Enumerate()
{
try
{
_lock.EnterReadLock();
foreach (T item in _list)
yield return item;
}
finally
{
_lock.ExitReadLock();
}
}
public IEnumerator<T> GetEnumerator()
=> Enumerate().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
=> Enumerate().GetEnumerator();
}
Неизменяемые коллекции
Так же существуют неизменяемые коллекции System.Collections.Immutable. Они тоже являются потокобезопасными, так как данные в них нельзя изменить, а следовательно к ним можно получать безопасный доступ из нескольких потоков. Подробнее почитать можно здесь.