Vb.net .NET以有序方式终止线程
目前,我有一个由生产者和消费者线程运行的RingBuffer 在寻找一种有序终止它们的方法时,我想我应该使用一个标志来指示生产者何时完成,然后在消费者中检查该标志以及需要写入的环形缓冲槽的数量。如果生产者已经完成,并且环形缓冲区没有需要写入的插槽,消费者可以终止 这很有效 但是,如果我通过插入睡眠来人为延长制作者所花的时间,消费者不会终止。我相信这是使用信号量的结果 这是我正在使用的代码。请注意,在写入所有插槽后,程序将“挂起”。生产者终止,但消费者“挂起” 如有任何关于有序终止两者的建议,将不胜感激 编辑-使用Henk建议的队列更新代码+1000分给第一个人,建议终止使用者/生产者线程的更好方法,而不是知道正在处理的项目的确切数量或返回null/nothing等值,指示队列中不存在更多项目(虽然这并不意味着它们还没有生产出来。) 编辑-我相信我已经找到了答案。只需将null或nothing传递给RingBuffer。为每个消费者排队,并捕获消费者中的null或nothing对象以终止它。希望有人发现这很有用Vb.net .NET以有序方式终止线程,vb.net,multithreading,Vb.net,Multithreading,目前,我有一个由生产者和消费者线程运行的RingBuffer 在寻找一种有序终止它们的方法时,我想我应该使用一个标志来指示生产者何时完成,然后在消费者中检查该标志以及需要写入的环形缓冲槽的数量。如果生产者已经完成,并且环形缓冲区没有需要写入的插槽,消费者可以终止 这很有效 但是,如果我通过插入睡眠来人为延长制作者所花的时间,消费者不会终止。我相信这是使用信号量的结果 这是我正在使用的代码。请注意,在写入所有插槽后,程序将“挂起”。生产者终止,但消费者“挂起” 如有任何关于有序终止两者的建议,将不
Imports System.Collections
Module Module1
Public Class RingBuffer
Private m_Capacity As Integer
Private m_Queue As Queue
Public Sub New(ByVal Capacity As Integer)
m_Capacity = Capacity
m_Queue = Queue.Synchronized(New Queue(Capacity))
End Sub
Public Sub Enqueue(ByVal value As Object)
SyncLock m_Queue.SyncRoot
If m_Queue.Count = m_Capacity Then
Threading.Monitor.Wait(m_Queue.SyncRoot)
End If
m_Queue.Enqueue(value)
Threading.Monitor.PulseAll(m_Queue.SyncRoot)
End SyncLock
End Sub
Public Function Dequeue() As Object
Dim value As Object = Nothing
SyncLock m_Queue.SyncRoot
If m_Queue.Count = 0 Then
Threading.Monitor.Wait(m_Queue.SyncRoot)
End If
value = m_Queue.Dequeue()
Console.WriteLine("Full Slots: {0} - Open Slots: {1}", m_Queue.Count, m_Capacity - m_Queue.Count)
Threading.Monitor.PulseAll(m_Queue.SyncRoot)
End SyncLock
Return value
End Function
End Class
Public Class Tile
Public buffer() As Byte
Public Sub New()
buffer = New Byte(1023) {}
End Sub
End Class
Public Sub Producer(ByVal rb As RingBuffer)
Dim enq As Integer = 0
Dim rng As New System.Security.Cryptography.RNGCryptoServiceProvider
For i As Integer = 0 To 1023
Dim t As New Tile
rng.GetNonZeroBytes(t.buffer)
rb.Enqueue(t)
enq += 1
Threading.Thread.Sleep(10)
Next i
rb.Enqueue(Nothing)
Console.WriteLine("Total items enqueued: " & enq.ToString())
Console.WriteLine("Done Producing!")
End Sub
Public Sub Consumer(ByVal rb As RingBuffer)
Dim deq As Integer = 0
Using fs As New IO.FileStream("c:\test.bin", IO.FileMode.Create)
While True
Dim t As Tile = rb.Dequeue()
If t Is Nothing Then Exit While
fs.Write(t.buffer, 0, t.buffer.Length)
deq += 1
Threading.Thread.Sleep(30)
End While
End Using
Console.WriteLine("Total items dequeued: " & deq.ToString())
Console.WriteLine("Done Consuming!")
End Sub
Sub Main()
Dim rb As New RingBuffer(1000)
Dim thrdProducer As New Threading.Thread(AddressOf Producer)
thrdProducer.SetApartmentState(Threading.ApartmentState.STA)
thrdProducer.Name = "Producer"
thrdProducer.IsBackground = True
thrdProducer.Start(rb)
Dim thrdConsumer As New Threading.Thread(AddressOf Consumer)
thrdConsumer.SetApartmentState(Threading.ApartmentState.STA)
thrdConsumer.Name = "Consumer"
thrdConsumer.IsBackground = True
thrdConsumer.Start(rb)
Console.ReadKey()
End Sub
End Module
如果我看一下消费者功能:
If rb.FullSlots = 0 And Threading.Interlocked.Read(ProducerFinished) = 0 Then
Exit While
End If
Dim t As Tile = rb.Read()
使用者可以找到rb.FullSlots=0,但ProducerFinished=False并继续读取()。在Read()内部,它等待writerSemaphore,但同时生产者可以完成并且永远不会释放writerSemaphore
所以(至少)制作人应该采取措施让读者在减少制作人完成后继续阅读
但我认为,如果你将这个“关闭”逻辑移动到环形缓冲区,你会得到更好的设计。在那里,你可以将它与可用的数据逻辑相结合。我想,只要我知道有多少项将提前生产,我就可以简单地预期生产者/消费者线程中会有那么多项,但必须有一种方法来为未知的对象执行此操作n个项目数…我建议更简单一些-围绕队列(T)构建一个类,并使用一个简单的布尔值进行关闭。使用内部syncRoot并使用Wait和Pulse处理空队列。您当前的方法似乎基于无锁设计(但使用锁:-)确实是:)谢谢Henk,我将尝试一下。