Я заметил, что вы можете вызвать Queue.Synchronize, чтобы получить объект с потоковой безопасностью, но тот же метод недоступен в Queue <T> . Кто-нибудь знает, почему? Кажется странным.
Почему в .NET нет единой синхронной очереди?
Ответ 1
Обновить - в .NET 4 теперь есть ConcurrentQueue<T>
в System.Collections.Concurrent, как описано здесь http://msdn.microsoft.com/en-us/library/dd267265.aspx. Интересно отметить, что его IsSynchronized метод (по праву) возвращает false.
ConcurrentQueue<T>
- это полная переделка исходного кода, создание копий очереди для перечисления и использование передовых методов без блокировки, таких как Interlocked.CompareExchange()
и Thread.SpinWait()
.
Остальная часть этого ответа по-прежнему актуальна, поскольку это связано с кончиной старых членов Synchronize() и SyncRoot и почему они не очень хорошо работают с точки зрения API.
Согласно комментарию Zooba, команда BCL решила, что слишком многие разработчики неправильно понимают цель Synchronize (и, в меньшей степени, SyncRoot)
Брайан Грункмайер описал это в блоге команды BCL пару лет назад: http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx
Ключевой проблемой является получение правильной детализации вокруг блокировок, когда некоторые разработчики наивно используют несколько свойств или методов в "синхронизированной" коллекции и считают, что их код является потокобезопасным. Брайан использует Queue в качестве своего примера,
if (queue.Count > 0) {
object obj = null;
try {
obj = queue.Dequeue();
Разработчики не поймут, что граф может быть изменен другим потоком до того, как был вызван Dequeue.
Принуждение разработчиков к использованию явного оператора блокировки во всей операции означает предотвращение этого ложного чувства безопасности.
Как упоминает Брайан, удаление SyncRoot было отчасти потому, что в основном оно было введено для поддержки Synchronized, но также и потому, что во многих случаях лучше выбрать объект блокировки - большую часть времени - либо сам экземпляр очереди, либо a
private static object lockObjForQueueOperations = new object();
в классе, которому принадлежит экземпляр очереди...
Этот последний подход обычно безопасен, поскольку он позволяет избежать некоторых других общих ловушек:
Как говорится, многопоточная обработка, и сделать это легко, может быть опасно.
Ответ 2
Возможно, вы обнаружите, что Parallel CTP стоит проверить; вот запись в блоге от парней, которые объединяют это довольно актуальное:
Перечисление параллельных коллекций
Это не совсем то же самое, но это может решить вашу большую проблему. (Они даже используют Queue<T>
по сравнению с ConcurrentQueue<T>
в качестве примера.)
Ответ 3
В .NET 4.0 есть
ConcurrentQueue<T>
в System.Collections.Concurrent
Ответ 4
(Я предполагаю, что вы имеете в виду Queue <T> для второго).
Я не могу конкретно ответить на этот вопрос, за исключением того, что свойства IsSynchronized и SyncRoot (но не синхронно() явно) наследуются от интерфейса ICollection. Ни один из общих коллекций не использует это, а ICollection <T> интерфейс не включает SyncRoot.
Что касается того, почему он не включен, я могу только предположить, что они не использовались ни в том смысле, который был разработан разработчиками библиотеки, либо просто не использовались достаточно, чтобы оправдать их сохранение в новых коллекциях.