2011-07-21 15 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

ロックされたリソースで問題が発生しました。ロックオブジェクトを同期ロックリソースとして使用していますが、これは共有スレッドである必要があります。 インスタンスフィールドにする必要があります。

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

同じロックオブジェクトをスレッド間でインスタンス変数にする必要があります。

4

問題は、各スレッドでロックするオブジェクトの新しいインスタンスを作成して使用することです。素朴な解決策は、lockObjectをローカル変数からクラス変数に昇格させることです。そうすれば、各スレッドは同じオブジェクトを使用してロックします。私はあなたが他の人のために1つの問題を交換したので(これほど重大ではないが)、これは素朴だと言う。新しい問題は、並列アルゴリズムをシリアルアルゴリズムにしたことです。これは、ある時点で1つのスレッドしか作業を行えないためです。

解決策は、が変更されている間にのみ、キューへのアクセスをロックすることです。次に、スレッドが同時に作業を実行できるように、ロック外のデキューされたオブジェクトを操作します。

.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 

私は完全にSyncLockを使用する必要がないようにConcurrentQueueを使用。私はCountdownEventを仕事項目が完了するのを待つよりスケーラブルな代替手段として使用しました。