Проблема в том, что вы создаете и используете новый экземпляр объекта для блокировки в каждом потоке. Наивным решением является продвижение lockObject
из локальной переменной в переменную класса. Таким образом, каждый поток использует один и тот же объект для блокировки. Я говорю, что это наивно, потому что вы обменяли одну проблему на другую (хотя и менее серьезную). Новая проблема заключается в том, что теперь вы сделали свой параллельный алгоритм последовательным алгоритмом, поскольку в любой момент времени только один поток может выполнять работу.
Решением будет блокировка доступа к очереди только в то время, когда она изменяется. Затем работайте с объектами, снятыми с очереди, вне блокировки, чтобы потоки могли выполнять работу одновременно.
Если доступен .NET 4.0, вы можете изменить код следующим образом.
Public Class Example
Private m_Queue As ConcurrentQueue(Of SomeObject) = New ConcurrentQueue(Of SomeObject)()
Public Shared Sub Main()
' Populate the queue here.
Dim finished = New CountdownEvent(1)
For i As Integer = 0 to 4
finsihed.AddCount()
ThreadPool.QueueUserWorkItem(AddressOf DoOne, finished)
Next
finished.Signal()
finished.Wait()
End Sub
Private Shared Sub DoOne(ByVal state As Object)
Try
Dim item As SomeObject = Nothing
Do While m_Queue.TryDequeue(item) Then
' Process the dequeued item here.
Loop
' There is nothing left so do something else now.
Finally
Dim finished = DirectCast(state, CountdownEvent)
finished.Signal()
End Try
End Sub
End Class
Я использовал ConcurrentQueue
, чтобы избежать необходимости использовать SyncLock
полностью. Я использовал CountdownEvent
в качестве более масштабируемой альтернативы для ожидания выполнения рабочих элементов.