2009-05-30 14 views
6

मैं एक संदेश कतार का लॉक-फ्री संस्करण लिखने का प्रयास कर रहा हूं जिसका उपयोग मैं संदेश पास करने के लिए करता हूं। थ्रेडिंग के बारे में जानने के लिए यह कुछ भी गंभीर नहीं है।मैं VB.net में अस्थिर के बराबर कैसे निर्दिष्ट करूं?

मुझे अपेक्षा है कि मेरा कोड सही है, सिवाय इसके कि निर्देशों को फिर से आदेश दिया गया है या रजिस्टरों में किया गया है। मुझे पता है कि मैं फिर से ऑर्डर करने के लिए मेमोरी बाधाओं का उपयोग कर सकता हूं, लेकिन मैं यह सुनिश्चित कैसे कर सकता हूं कि मूल्य तुरंत स्मृति में लिखे गए हैं?

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 

उत्तर

3

मैं इस विषय पर एक विशेषज्ञ नहीं हूं इसलिए उम्मीद है कि अगर कोई गलत है तो कोई और मुझे सही करेगा। जो मैं समझता हूं, उससे स्मृति अनुकूलन का मुद्दा वर्तमान में एक सैद्धांतिक है और जरूरी नहीं कि कुछ वास्तविकता में हो। लेकिन ऐसा कहा जाता है कि, मुझे लगता है कि आपकी मेमोरी एक्सेस के लिए इंटरलाक्ड एपीआई का उपयोग करके (मेमोरीबैरियर के बावजूद) आप प्रभावित नहीं होंगे।

दुर्भाग्य से वीबी.नेट में अस्थिरता के बराबर नहीं है। यह एक सामान्य विशेषता से सजाया नहीं गया है, बल्कि एक विशेष संकलक उत्पन्न संशोधक है। आपको इस तरह के क्षेत्र के साथ एक प्रकार को उत्सर्जित करने के लिए प्रतिबिंब का उपयोग करना होगा।

यहां एक संसाधन है जिसे मैं अक्सर संदर्भित करता हूं जब मेरे पास .NET ढांचे में थ्रेडिंग के बारे में प्रश्न हैं। यह बहुत लंबा है लेकिन उम्मीद है कि आप इसे उपयोगी पाएंगे।

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

+0

सैद्धांतिक एक? जैसे, आपका मतलब है, महत्वपूर्ण अनुभाग 512+ सीपीयू मशीनों के लिए पूर्ण प्रदर्शन हत्यारे नहीं हैं? – EFraim

10

सी # के VB.NET में volatile कीवर्ड की कोई समकक्ष नहीं है। इसके बजाए अक्सर 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 

इसके अलावा इस विषय पर एक उपयोगी ब्लॉग post है।

+1

उपयोगी, लेकिन मैं अभी भी उलझन में हूं कि रीड मेमोरी बाधा पहले की बजाय क्यों आती है, और इसके विपरीत लिखने के लिए। –

+0

@Strilanc: नीचे दिए गए उत्तर पर दस्तावेज़ से: प्रत्येक अनुक्रम जो निर्देश अनुक्रम में अस्थिर पढ़ने के बाद होता है, स्मृति मॉडल में अस्थिर पढ़ने के बाद भी होता है - उन्हें अस्थिर पढ़ने से पहले पुन: व्यवस्थित नहीं किया जा सकता है।एक अस्थिर लेखन दूसरे तरीके से जाता है - निर्देश लिखने में अस्थिर लेखन से पहले प्रत्येक लेखन स्मृति मॉडल में अस्थिर लेखन से पहले होता है। – EFraim

-1

तुम भी) "वाष्पशील" Thread.VolatileRead() और Thread.VolatileWrite (प्रयोग करने के लिए एक विशेषता लिख ​​सकते हैं और जैसे उस विशेषता के साथ सभी गुण/चर बना सकते हैं:

<Volatile()> 
Protected Property SecondsRemaining as Integer 

लिखा इस कहीं लेकिन अभी यह पता लगाने के लिए ...

2

.NET 4.5 में शुरू नहीं कर पा रहे हैं, वे बीसीएल के लिए दो नई विधियां जोड़ volatile कीवर्ड अनुकरण करने के लिए: Volatile.Read और Volatile.Write। उन्हें volatile फ़ील्ड पढ़ने/लिखने के बराबर होना चाहिए। आप स्पष्ट रूप से उन्हें VB.NET में उपयोग कर सकते हैं। वे क्योंकि वे पूर्ण बाड़ के बजाय आधा बाड़ का उपयोग बेहतर (जहां बेहतर == तेजी) Thread.VolatileRead/Thread.VolatileWrite से कर रहे हैं।

संबंधित मुद्दे