7

メッセージ パッシングに使用する呼び出しキューのロックフリー バージョンを作成しようとしています。これは深刻なことではなく、スレッドについて学ぶためのものです。

命令が並べ替えられているか、レジスタで実行されている場合を除いて、コードが正しいと比較的確信しています。メモリバリアを使用して並べ替えを停止できることはわかっていますが、値がすぐにメモリに書き込まれるようにするにはどうすればよいですか?

Public Class CallQueue
    Private first As New Node(Nothing) 'owned by consumer'
    Private last As Node = first 'owned by producers'
    Private Class Node
        Public ReadOnly action As Action
        Public [next] As Node
        Public Sub New(ByVal action As Action)
            Me.action = action
        End Sub
    End Class

    Private _running As Integer
    Private Function TryAcquireConsumer() As Boolean
        Threading.Thread.MemoryBarrier()

        'Dont bother acquiring if there are no items to consume'
        'This unsafe check is alright because enqueuers call this method, so we never end up with a non-empty idle queue'
        If first.next Is Nothing Then Return False

        Threading.Thread.MemoryBarrier()

        'Try to acquire'
        Return Threading.Interlocked.Exchange(_running, 1) = 0
    End Function
    Private Function TryReleaseConsumer() As Boolean
        Do
            Threading.Thread.MemoryBarrier()

            'Dont release while there are still things to consume'
            If first.next IsNot Nothing Then Return False

            Threading.Thread.MemoryBarrier()

            'Release'
            _running = 0

            Threading.Thread.MemoryBarrier()

            'It is possible that a new item was queued between the first.next check and releasing'
            'Therefore it is necessary to check if we can re-acquire in order to guarantee we dont leave a non-empty queue idle'
            If Not TryAcquireConsumer() Then Return True
        Loop
    End Function

    Public Sub QueueAction(ByVal action As Action)
        'Enqueue'
        'Essentially, this works because each node is returned by InterLocked.Exchange *exactly once*'
        'Each node has its .next property set exactly once, and also each node is targeted by .next exactly once, so they end up forming a valid tail'
        Dim n = New Node(action)
        Threading.Interlocked.Exchange(last, n).next = n

        'Start the consumer thread if it is not already running'
        If TryAcquireConsumer() Then
            Call New Threading.Thread(Sub() Consume()).Start()
        End If
    End Sub
    Private Sub Consume()
        'Run until queue is empty'
        Do Until TryReleaseConsumer()
            first = first.next
            Call first.action()
        Loop
    End Sub
End Class
4

6 に答える 6

11

volatileVB.NET には、C# のキーワードに相当するものはありません。代わりに、しばしば推奨されるのはMemoryBarrierの使用です。ヘルパー メソッドも次のように記述できます。

Function VolatileRead(Of T)(ByRef Address As T) As T
    VolatileRead = Address
    Threading.Thread.MemoryBarrier()
End Function

Sub VolatileWrite(Of T)(ByRef Address As T, ByVal Value As T)
    Threading.Thread.MemoryBarrier()
    Address = Value
End Sub

また、このテーマに関する有用なブログ投稿もあります。

于 2009-05-30T08:27:37.280 に答える
6

BCL の使用方法Thread.VolatileRead()と方法。VolatileWrite()

http://msdn.microsoft.com/en-us/library/system.threading.thread.volatileread.aspx

于 2010-11-09T00:36:48.457 に答える
4

.NET 4.5 以降、volatileキーワードをシミュレートする 2 つの新しいメソッドが BCL に追加されました: Volatile.ReadVolatile.Writevolatileそれらは、フィールドの読み取り/書き込みと完全に同等でなければなりません。VB.NET でそれらを明確に使用できます。フルフェンスの代わりにハーフフェンスを使用するため、 /よりも優れています(より良い==高速) 。Thread.VolatileReadThread.VolatileWrite

于 2015-08-16T06:15:16.510 に答える
3

私はこのテーマの専門家ではないので、間違っている場合は誰かが訂正してくれることを願っています。私が理解していることから、メモリの最適化の問題は現在のところ理論的なものであり、必ずしも実際に発生するとは限りません。しかし、そうは言っても、(MemoryBarrier に関係なく) メモリ アクセスに Interlocked API を使用しても影響はないと思います。

残念ながら、VB.NET には volatile に相当するものはありません。これは通常の属性で装飾されたものではなく、コンパイラによって生成された特別な修飾子です。この種のフィールドを持つ型を発行するには、Reflection を使用する必要があります。

これは、.NET フレームワークでのスレッド化について質問があるときによく参照するリソースです。非常に長いですが、お役に立てれば幸いです。

http://www.yoda.arachsys.com/csharp/threads/printable.shtml

于 2009-05-30T06:57:00.707 に答える
-1

Thread.VolatileRead() と Thread.VolatileWrite() を使用して「揮発性」の属性を記述し、その属性を持つすべてのプロパティ/変数を次のようにすることもできます。

<Volatile()>
Protected Property SecondsRemaining as Integer

どこかに書いてあるのですが、今は見つけられません…

于 2013-12-20T16:52:13.097 に答える