Потокобезопасный GetEnumerator
Имеют ли Mutex и lock одинаковый эффект в пределах одного процесса?
Если я хочу создать потокобезопасную коллекцию с использованием внутри списка, будет ли такой вызов безопасен (за время пока элементы коллекции будет перечисляться в цикле, сама коллекция может много раз измениться):
public IEnumerator GetEnumerator() {
lock (SyncObj) return InnerList.GetEnumerator();
}
Может нужно сделать так:
public IEnumerator GetEnumerator() {
lock (SyncObj) return new List<object>(InnerList).GetEnumerator();
}
Ответы (1 шт):
Имеют ли Mutex и lock одинаковый эффект в пределах одного процесса?
Эффект да, скорость - нет. Самый быстрый из двух будет lock.
Еще быстрее будет Reader/Writer lock, например на базе ReaderWriterLockSlim, так как он позволит хотя-бы безопасно читать коллекцию в многопоточке нескольким потокам сразу (пример реализации).
Если я хочу создать потокобезопасную коллекцию с использованием внутри списка, будет ли такой вызов безопасен
Первый вариант безопасен не будет, так как само перечисление будет происходить за пределами лока, а значит ваш SyncObj будет свободен для взятия другим локом. Но я бы в качестве снапшота использовал массив, а не список, он более легковесный.
Второй вариант делает снапшот коллекции под локом и отдает энумератор с нее, отличный вариант в плане того, что он не лочит саму коллекцию во время перечисления.
Но есть еще вариант
public IEnumerator<T> GetEnumerator()
{
lock (SyncObj)
{
foreach (T item in InnerList)
yield return item;
}
}
Плюс - копия коллекции не будет создана, коллекция не будет изменена во время перечисления. Минус - коллекция будет заблокирована на время перечисления.
Вам решать, что из этого лучше сработает.