Это может быть плохая практика, но Вы рассмотрели включая его встроенный?
do
SyncLock MyQueue
MyQueue.Enqueue(Obj)
End SyncLock
End Sub
Один набор инструкций не означает, что он является потокобезопасным. Что касается инструкций, у вас всегда есть только один набор.
Теперь, глядя на пример кода, который вы предоставили, невозможно сказать, является ли он потокобезопасным или нет. Все стандартные коллекции .NET, в том числе Queue, сами по себе не являются потокобезопасными, но предоставляют вам доступ к синхронизированной версии самих себя.
Что касается производительности, конечно, производительность падает, насколько она велика - это зависит от объем замка и некоторые другие вещи. В частности, использование глобальных блокировок в веб-приложении может стать серьезным узким местом при большой нагрузке
Нет, это не потокобезопасно.
Открытые статические (общие в Visual Basic) члены этого типа безопасны для многопоточных операций. Не гарантируется, что члены экземпляра будут потокобезопасными.
С сайта MSDN .
Я бы предложил добавить объект для представления дескриптора синхронизации для вашего объекта
Dim SyncHandle as Object = new Object()
И изменить ваш метод как такой
Public Sub InsertIntoQueue(Object item)
SyncLock SyncHandle
MyQueue.Enqueue(item)
End SyncLock
End Sub
Я не специалист по безопасности потоков, но я пытаюсь узнать как можно больше по этому поводу.
Раньше я думал (как и вы), что эта операция может быть потокобезопасным, так как просто записываются данные в очередь в разных потоках, и удаление из очереди не выполняется. Но, как кто-то объяснил здесь (и везде в документации MSDN):
Public static (Shared in Visual Basic) члены этого типа безопасны для многопоточные операции. Пример членам не гарантируется быть потокобезопасный.
Это означает, что, возможно, внутренне MyQueue.Enqueue (Obj)
выполняется следующим образом:
Если это будет сделано таким образом, у вас будут проблемы с потоками, потому что, как вы видите, вы можете перезаписать одну и ту же позицию в очереди двумя потоками, потому что один пишет, а другой сделал то же самое. но при этом уже не удалось увеличить указатель.
Имея это в виду, у вас есть несколько вариантов, как указано здесь, блокировка метода Enqueue (), использование Queue.Synchronized () или, может быть, даже проще, но с большим влиянием на производительность, блокировка частного свойства при доступе к объекту Queue таким способом (потому что все, что вы делаете с Queue, не будет потокобезопасным):
Private ReadOnly Property MyQueue() as Queue
Get
SyncLock (m_myQueueLock)
Return m_myQueue
EndSyncLock
End Get
End Property
Надеюсь, это поможет!
Рискуя немного отклониться от темы OP, следует рассмотреть другие методы очереди. Я предполагаю, что существует по крайней мере один поток, удаляющий объекты из очереди, и, возможно, вы также проверяете, пуста ли очередь?
С точки зрения удаления из очереди, если у вас есть более одного потока, удаляющего из очереди, и они проверяют, есть ли очередь не является пустым перед вызовом dequeue (чтобы предотвратить исключение недопустимой операции), тогда вполне вероятно, что один поток (поток a) может исключить из очереди последний элемент в очереди, между другим потоком (поток b), читающим, что очередь не пуста и он вызывает dequeue, таким образом, поток a вызовет исключение недопустимой операции.
Вы можете установить блокировку вокруг проверки на пустоту и dequeue, чтобы обойти это.