Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在VB.net中指定volatile的等效项?_Vb.net_Multithreading_Volatile_Lock Free - Fatal编程技术网

如何在VB.net中指定volatile的等效项?

如何在VB.net中指定volatile的等效项?,vb.net,multithreading,volatile,lock-free,Vb.net,Multithreading,Volatile,Lock Free,我正在尝试编写用于消息传递的调用队列的无锁版本。这不是为了什么严肃的事情,只是为了学习线程 我相对确信我的代码是正确的,除非指令是在寄存器中重新排序或完成的。我知道我可以使用内存障碍来停止重新排序,但如何确保立即将值写入内存 Public Class CallQueue Private first As New Node(Nothing) 'owned by consumer' Private last As Node = first 'owned by producers'

我正在尝试编写用于消息传递的调用队列的无锁版本。这不是为了什么严肃的事情,只是为了学习线程

我相对确信我的代码是正确的,除非指令是在寄存器中重新排序或完成的。我知道我可以使用内存障碍来停止重新排序,但如何确保立即将值写入内存

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

我不是这方面的专家,所以如果我错了,希望其他人会纠正我。据我所知,内存优化问题目前只是一个理论问题,不一定会在现实中发生。但话虽如此,我认为通过使用互锁API访问内存(不管内存载体是什么),您不会受到影响

不幸的是,VB.NET中没有volatile的等价物。它不是用普通属性修饰的,而是一个特殊的编译器生成的修饰符。您需要使用反射来发出具有此类字段的类型

当我对.NET framework中的线程有疑问时,我经常参考以下资源。它很长,但希望你会发现它很有用

在VB.NET中没有C#的
volatile
关键字的等价物。相反,我们经常推荐的是使用。也可以编写助手方法:

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

关于这个主题还有一个有用的博客。

使用BCL中的
Thread.volatireRead()
volatireWrite()
方法


您还可以使用Thread.volatireRead()和Thread.volatireWrite()为“Volatile”编写一个属性,并使所有具有该属性的属性/变量如下所示:

<Volatile()>
Protected Property SecondsRemaining as Integer

受保护的属性seconds以整数形式保留

在某个地方写了这个,但现在似乎找不到…

从.NET 4.5开始,他们在BCL中添加了两个新方法来模拟
volatile
关键字:and。它们应该完全等同于读取/写入
volatile
字段。您可以在VB.NET中清楚地使用它们。它们比
线程.volatireRead
/
线程.volatireWrite
更好(其中更好==更快),因为它们使用半围栏而不是全围栏。

Mono.Cecil阅读器代码将字段类型设置为
RequiredModifierType,修饰符类型为System.Runtime.CompilerServices.IsVolatile。

很有用,但我仍然不明白为什么读取内存障碍出现在后面而不是前面,写操作也是如此。@Strilan:从下面答案的文档中可以看出:指令序列中的易失性读取之后发生的每次读取也发生在内存模型中的易失性读取之后-它们不能在易失性读取之前重新排序。易失性写入则相反——在指令序列中的易失性写入之前发生的每一次写入也发生在内存模型中的易失性写入之前。@CraigGidney:这看起来可能会给您提供获取/释放顺序语义,您需要将负载保持在“关键部分”之前以及之后的发布商店。顺序一致性存储需要在存储之后设置一个完整的内存屏障(如x86上的
mfence
,而不仅仅是编译器重新排序栏)。理论上的?比如,你的意思是,对于512+CPU的机器来说,关键部分不是绝对的性能杀手?