2011-07-21 90 views
4

我想在VB中運行多線程控制檯應用程序,並且正在進行線程交叉。基本上我想運行5個線程,讓他們不斷訪問一個隊列,處理並重復,直到沒有剩下任何東西。當所有線程都處理完畢後,我希望他們能夠做其他事情。我試圖使用SyncLock來阻止多線程訪問,但似乎沒有工作。任何幫助,將不勝感激!VB.Net中的線程安全

Dim iThread As Integer 
Dim manualEvents(4) As ManualResetEvent 

Sub Main() 
    For i = 0 To 4 
     manualEvents(i) = New ManualResetEvent(False) 
     ThreadPool.QueueUserWorkItem(AddressOf DoOne) 
    Next 

    For Each handle As WaitHandle In manualEvents 
     handle.WaitOne() 
    Next 

    ' do other stuff 
EndSub 

Private Sub DoOne() 
    Dim lockObject As New Object() 
    SyncLock (lockObject) 
     If QueryQueue.DoOne() Then 
      DoOne() 
     Else 
      manualEvents(iThread).Set() 
      iThread = iThread + 1 
     End If 
    End SyncLock 
End Sub 

回答

4

的問題是與鎖定的資源,你使用lockObject作爲應該accros線程共享一個同步鎖資源。 你必須使它成爲一個實例字段。

Private Shared lockObject As New Object() 
Private Sub DoOne() 
    SyncLock (lockObject) 
    If QueryQueue.DoOne() Then 
     DoOne() 
    Else 
     manualEvents(iThread).Set() 
     iThread = iThread + 1 
    End If 
    End SyncLock 
End Sub 
+0

該解決方案將使事情線程安全的,但換來的,因爲所有的* *線程現在已經在排隊等候執行任何有用的工作......或與此有關的任何工作移除所有的並行性。 –

2

您需要通過將其作爲實例變量跨線程共享相同的lockObject。

4

問題是您正在創建並使用一個對象的新實例來鎖定每個線程。天真的解決方案是將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作爲等待工作項目完成的更具擴展性的替代方案。