Что вы имеете в виду под fail ?
Возьмите следующий пример:
var queue = new Queue<string>();
string temp = queue.Dequeue();
// do something with temp
Приведенный выше код сгенерирует исключение, так как мы пытаемся удалить изпустая очередь.Теперь, если вместо этого вы используете ConcurrentQueue<T>
:
var queue = new ConcurrentQueue<string>();
string temp;
if (queue.TryDequeue(out temp))
{
// do something with temp
}
Приведенный выше код не сгенерирует исключение.Очередь по-прежнему не сможет удалить элемент из очереди, но код не будет сгенерирован при выдаче исключения.Реальное использование этого становится очевидным в многопоточной среде.Код для несовместимого Queue<T>
обычно будет выглядеть примерно так:
lock (queueLock)
{
if (queue.Count > 0)
{
string temp = queue.Dequeue();
// do something with temp
}
}
Чтобы избежать условий гонки, нам нужно использовать блокировку, чтобы гарантировать, что с очередью ничего не произойдет во время, когдапроходит проверку Count
, звоните Dequeue
.С ConcurrentQueue<T>
нам не нужно проверять Count
, но вместо этого мы можем вызвать TryDequeue
.
Если вы изучите типы, найденные в пространстве имен Systems.Collections.Concurrent
, вы обнаружите, что многие из нихобернуть две операции, которые обычно вызываются последовательно, и для которых традиционно требуется блокировка (Count
с последующим Dequeue
в ConcurrentQueue<T>
, GetOrAdd
в ConcurrentDictionary<TKey, TValue>
заменяет последовательности вызова ContainsKey
, добавление элемента и получение егои т. д.).