vb.net에서 휘발성을 동등하게 지정하려면 어떻게합니까?
-
06-09-2019 - |
문제
메시지 전달에 사용하는 호출 대기열의 잠금 장치 버전을 작성하려고합니다. 이것은 스레딩에 대해 배우는 것만으로도 심각한 것이 아닙니다.
지침이 레지스터에서 다시 주문되거나 완료된 경우를 제외하고 내 코드가 정확하다고 확신합니다. 메모리 장벽을 사용하여 재정렬을 중지 할 수 있다는 것을 알고 있지만, 값이 즉시 메모리에 기록되도록하려면 어떻게해야합니까?
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
해결책
사용 Thread.VolatileRead()
그리고 VolatileWrite()
BCL의 방법.
http://msdn.microsoft.com/en-us/library/system.threading.thread.volatileread.aspx
다른 팁
C#과 동등한 것은 없습니다 volatile
vb.net의 키워드. 대신에 종종 권장되는 것은 사용입니다 메모리 배리어. 도우미 방법도 작성할 수 있습니다.
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
또한 유용한 블로그가 있습니다 게시하다 이 주제에 대해.
.NET 4.5에서 시작하여 BCL에 두 가지 새로운 방법을 추가하여 volatile
예어: 휘발성. 읽기 그리고 volatile.write. 그들은 읽기/쓰기와 완전히 동일해야합니다. volatile
필드. vb.net에서 명확하게 사용할 수 있습니다. 그들은 더 나은 (어디 더 나은 == 더 빠르게)보다 Thread.VolatileRead
/Thread.VolatileWrite
전체 울타리 대신 반 울타리를 사용하기 때문입니다.
나는이 주제에 대한 전문가가 아니므로 내가 틀렸다면 다른 사람이 나를 바로 잡을 수 있기를 바랍니다. 내가 이해 한 바에 따르면, 메모리 최적화 문제는 현재 이론적 인 문제이며 반드시 실제로 일어날 일은 아닙니다. 그러나 메모리 배거에 관계없이 메모리 액세스에 연동 API를 사용하면 영향을받지 않을 것이라고 생각합니다.
불행히도 VB.NET에는 휘발성과 동등한 것이 없습니다. 일반적인 속성으로 장식되지는 않지만 오히려 특수 컴파일러 생성 수정 자입니다. 이런 종류의 필드가있는 유형을 방출하려면 반사를 사용해야합니다.
다음은 .NET Framework에서 스레딩에 대한 질문이있을 때 자주 참조하는 리소스입니다. 매우 길지만 유용하게 찾을 수 있기를 바랍니다.
mono.cecil reader 코드는 fieldType를 system.runtime.compilerservices.isvolatile으로 modifiertype를 사용하여 QuessedModifierType로 만듭니다.
또한 thread.volatileRead () 및 thread.volatilewrite ()를 사용하여 "휘발성"에 대한 속성을 작성하고 다음과 같은 속성으로 모든 속성/변수를 만들 수 있습니다.
<Volatile()>
Protected Property SecondsRemaining as Integer
이것을 어딘가에 썼지 만 지금은 찾을 수없는 것 같습니다 ...