私はさまざまなソースからのメッセージを簡単なリストに入れるアプリケーションサービスを提供しています。独自のスレッドで実行されるサービスは、定期的にリスト内のすべてのメッセージをさまざまなファイルに処理します。ソースごとに1つのファイルが作成され、サイズごとに管理されます。リストをロックする前後に再確認する必要がありますか?
私の質問は、メッセージをチェックし、リストにアクセスするコードの周りにロックを実行する適切な方法についてです。リストにアクセスする場所は2つだけです。 1つはメッセージがリストに追加され、もう1つはメッセージがリストから処理リストにダンプされる場所です。
リストにメッセージを追加:
リストを処理Public Sub WriteMessage(ByVal messageProvider As IEventLogMessageProvider, ByVal logLevel As EventLogLevel, ByVal message As String)
SyncLock _SyncLockObject
_LogMessages.Add(New EventLogMessage(messageProvider, logLevel, Now, message))
End SyncLock
End Sub
:
Dim localList As New List(Of EventLogMessage)
SyncLock _SyncLockObject
If (_LogMessages.Count > 0) Then
localList.AddRange(_LogMessages)
_LogMessages.Clear()
End If
End SyncLock
' process list into files...
は、私の質問は以下のとおりです。私はリストを処理していたとき、私は以下を参照してください、二重のチェックを行う必要がありますか?なぜ?それともなぜですか?そして、ロックの外でリストのcountプロパティにアクセスする際に危険がありますか?メソッドの方が効率的か、効率的か?なぜ?それともなぜですか?
Dim localList As New List(Of EventLogMessage)
If (_LogMessages.Count > 0) Then
SyncLock _SyncLockObject
If (_LogMessages.Count > 0) Then
localList.AddRange(_LogMessages)
_LogMessages.Clear()
End If
End SyncLock
End If
' process list into files...
私は処理関数の外に、リストだけ成長できる、という事実与えられた二重のチェックを行う場合は、この特定のケースでは、それは問題ではないかもしれないことを理解しています。しかし、これは私の実際の例であり、私はスレッディングの詳細について学びたいと思っています。
は「アライグマ」、およびいくつかの実験的なプログラミングをありがとう、...任意の洞察力のために、事前にいくつかのさらなる研究の後
をありがとう、私はさらにいくつかの考えを持っています。
ReaderWriterLockSlimに関して、私はうまくいくように見える次の例を持っています。これにより、リスト内のメッセージ数や他のコードとの干渉なく、リスト内のメッセージ数を読むことができます。リストを処理したいときは、ロックを書き込みモードにアップグレードし、メッセージを処理リストにダンプし、読み取り/書き込みロックの外で処理して、追加または読み込みが必要な他のスレッドをブロックしません、より多くのメッセージ。
この例では、Typeを他のメタデータとともに使用していた前の例とは異なり、メッセージのためのより簡単な構成を使用しています。
Private _ReadWriteLock As New Threading.ReaderWriterLockSlim()
Private Sub Process()
' create local processing list
Dim processList As New List(Of String)
Try
' enter read lock mode
_ReadWriteLock.EnterUpgradeableReadLock()
' if there are any messages in the 'global' list
' then dump them into the local processing list
If (_Messages.Count > 0) Then
Try
' upgrade to a write lock to prevent others from writing to
' the 'global' list while this reads and clears the 'global' list
_ReadWriteLock.EnterWriteLock()
processList.AddRange(_Messages)
_Messages.Clear()
Finally
' alway release the write lock
_ReadWriteLock.ExitWriteLock()
End Try
End If
Finally
' always release the read lock
_ReadWriteLock.ExitUpgradeableReadLock()
End Try
' if any messages were dumped into the local processing list, process them
If (processList.Count > 0) Then
ProcessMessages(processList)
End If
End Sub
Private Sub AddMessage(ByVal message As String)
Try
' enter write lock mode
_ReadWriteLock.EnterWriteLock()
_Messages.Add(message)
Finally
' always release the write lock
_ReadWriteLock.ExitWriteLock()
End Try
End Sub
私はこの技術で唯一の問題は、開発者がロックの取得と解放について勤勉でなければならないということです。そうしないと、デッドロックが発生します。
これがSyncLockを使用するよりも効率的かどうかに関しては、私は本当に言えませんでした。この特定の例とその使用法については、いずれか十分であると信じています。他の誰かがそれを変更している間にカウントを読んでいるという理由で、 'coon'が与えたのは二重チェックではありません。この例では、SyncLockは同じ機能を提供します。しかし、若干複雑なシステムでは、複数のソースがリストを読み書きする可能性があるため、ReaderWriterLockSlimが理想的です。
BlockingCollectionリストに関して、次の例は上記のように動作します。
Private _Messages As New System.Collections.Concurrent.BlockingCollection(Of String)
Private Sub Process()
' process each message in the list
For Each item In _Messages
ProcessMessage(_Messages.Take())
Next
End Sub
Private Sub AddMessage(ByVal message As String)
' add a message to the 'global' list
_Messages.Add(message)
End Sub
シンプルそのもの...
あなたはサービスのアーキテクチャに対してどれだけのコントロールを持っていますか?これは、MSMQを使用して重い持ち上げを行うことができたようです。 http://msdn.microsoft.com/en-us/library/ms789048.aspx – Trevor
私はサービスを言うとき、アプリケーションの内部で開始されたクラスを意味します。スレッドは、Windowsサービスではなく、アプリケーションの他の部分によって与えられたメッセージを定期的に処理します。汎用化されたメッセージハンドラ(アプリケーション内に完全にカプセル化され、独自のバックグラウンドスレッドで実行される場合)。この「サービス」は、1)メッセージを作成するための簡単な方法を提供すること、および2)メッセージの記憶域が多すぎる記憶領域を消費するのを防ぐことを課されます。 また、アプリケーション間メッセージングの必要はありません。 –
このアプリケーションでは、メッセージに誤った用語が使用されている可能性があります。ログされたイベントほどメッセージではありません。メッセージを作成したアプリケーションまたはモジュールに固有の、関連する「デバッグ」、「メッセージ」、「警告」または「エラー」ログイベント。 –