.NET - Очередь. Ставить в очередь ориентированный на многопотоковое исполнение метод?

Это может быть плохая практика, но Вы рассмотрели включая его встроенный?

5
задан Brian Webster 22 August 2013 в 15:26
поделиться

6 ответов

Использовать оболочку Queue.Synchronized .

8
ответ дан 18 December 2019 в 11:58
поделиться

do

SyncLock MyQueue
   MyQueue.Enqueue(Obj)
End SyncLock

End Sub

2
ответ дан 18 December 2019 в 11:58
поделиться

Один набор инструкций не означает, что он является потокобезопасным. Что касается инструкций, у вас всегда есть только один набор.

Теперь, глядя на пример кода, который вы предоставили, невозможно сказать, является ли он потокобезопасным или нет. Все стандартные коллекции .NET, в том числе Queue, сами по себе не являются потокобезопасными, но предоставляют вам доступ к синхронизированной версии самих себя.

Что касается производительности, конечно, производительность падает, насколько она велика - это зависит от объем замка и некоторые другие вещи. В частности, использование глобальных блокировок в веб-приложении может стать серьезным узким местом при большой нагрузке

1
ответ дан 18 December 2019 в 11:58
поделиться

Нет, это не потокобезопасно.

Открытые статические (общие в Visual Basic) члены этого типа безопасны для многопоточных операций. Не гарантируется, что члены экземпляра будут потокобезопасными.

С сайта MSDN .

Я бы предложил добавить объект для представления дескриптора синхронизации для вашего объекта

Dim SyncHandle as Object = new Object()

И изменить ваш метод как такой

Public Sub InsertIntoQueue(Object item)
    SyncLock SyncHandle 
       MyQueue.Enqueue(item)
    End SyncLock
End Sub
4
ответ дан 18 December 2019 в 11:58
поделиться

Я не специалист по безопасности потоков, но я пытаюсь узнать как можно больше по этому поводу.

Раньше я думал (как и вы), что эта операция может быть потокобезопасным, так как просто записываются данные в очередь в разных потоках, и удаление из очереди не выполняется. Но, как кто-то объяснил здесь (и везде в документации MSDN):

Public static (Shared in Visual Basic) члены этого типа безопасны для многопоточные операции. Пример членам не гарантируется быть потокобезопасный.

Это означает, что, возможно, внутренне MyQueue.Enqueue (Obj) выполняется следующим образом:

  1. Поместить данные в Queue ();
  2. Увеличить указатель очереди;

Если это будет сделано таким образом, у вас будут проблемы с потоками, потому что, как вы видите, вы можете перезаписать одну и ту же позицию в очереди двумя потоками, потому что один пишет, а другой сделал то же самое. но при этом уже не удалось увеличить указатель.

Имея это в виду, у вас есть несколько вариантов, как указано здесь, блокировка метода Enqueue (), использование Queue.Synchronized () или, может быть, даже проще, но с большим влиянием на производительность, блокировка частного свойства при доступе к объекту Queue таким способом (потому что все, что вы делаете с Queue, не будет потокобезопасным):

Private ReadOnly Property MyQueue() as Queue
Get
    SyncLock (m_myQueueLock)
        Return m_myQueue
    EndSyncLock
End Get
End Property

Надеюсь, это поможет!

0
ответ дан 18 December 2019 в 11:58
поделиться

Рискуя немного отклониться от темы OP, следует рассмотреть другие методы очереди. Я предполагаю, что существует по крайней мере один поток, удаляющий объекты из очереди, и, возможно, вы также проверяете, пуста ли очередь?

С точки зрения удаления из очереди, если у вас есть более одного потока, удаляющего из очереди, и они проверяют, есть ли очередь не является пустым перед вызовом dequeue (чтобы предотвратить исключение недопустимой операции), тогда вполне вероятно, что один поток (поток a) может исключить из очереди последний элемент в очереди, между другим потоком (поток b), читающим, что очередь не пуста и он вызывает dequeue, таким образом, поток a вызовет исключение недопустимой операции.

Вы можете установить блокировку вокруг проверки на пустоту и dequeue, чтобы обойти это.

0
ответ дан 18 December 2019 в 11:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: