2009-11-02 3 views
5

Предположим, что у меня есть модуль, в котором есть очередь..NET - безопасен ли метод Queue.Enqueue?

Для других лиц к Епдиеему, они должны пройти через функцию:

public sub InsertIntoQueue(Obj) 
    MyQueue.Enqueue(Obj) 
end sub 

Если я несколько потоков работают, и они хотят, чтобы позвонить InsertIntoQueue(), это считается поточно?

У меня создается впечатление, что в памяти требуется только одна копия инструкций в памяти, необходимых для выполнения функции InsertIntoQueue(), которая заставила бы меня думать, что это потокобезопасность.

Однако интересно, что происходит, когда два потока пытаются запустить функцию одновременно?

Является ли этот поток безопасным, а если нет, то как я могу сделать его потокобезопасным? (и каковы были бы последствия для скорости и использования памяти)

ответ

4

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

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

От MSDN Site.

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

Dim SyncHandle as Object = new Object() 

и модифицировать свой метод как таковой

Public Sub InsertIntoQueue(Object item) 
    SyncLock SyncHandle 
     MyQueue.Enqueue(item) 
    End SyncLock 
End Sub 
1

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

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

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

2

сделать

SyncLock MyQueue 
    MyQueue.Enqueue(Obj) 
End SyncLock 

End Sub

0

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

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

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

This и this интересные статьи о безопасности потока, а также я могу рекомендовать чтение this и/или this, пока они не все в vb.net они объясняют резьбы в деталях.

+0

Мой план состоял в том, чтобы иметь несколько потоков Enqueuing и один поток, блокирующий и очищающий всю очередь через определенные промежутки времени. –

+0

Если вы заблокируете, пока вы обрабатываете все объекты в очереди, все потоки, которые находятся в очереди, будут блокированы (если они будут пытаться вставить в очередь) до тех пор, пока не закончится поток детекции, вам может быть лучше заблокировать только пустую проверку и деактивацию каждого объект, а не всю обработку очереди. – Matt

0

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

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

Открытый статический (Shared в Visual Basic) члены этого типа являются безопасными для многопоточных операций. Участник не может быть защищен от ответственности. .

Это означает, что, возможно, внутренне MyQueue.Enqueue(Obj) делается так:

  1. Put данные по очереди();
  2. Augment Queue pointer;

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

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

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

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

Смежные вопросы