Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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 .NET以有序方式终止线程_Vb.net_Multithreading - Fatal编程技术网

Vb.net .NET以有序方式终止线程

Vb.net .NET以有序方式终止线程,vb.net,multithreading,Vb.net,Multithreading,目前,我有一个由生产者和消费者线程运行的RingBuffer 在寻找一种有序终止它们的方法时,我想我应该使用一个标志来指示生产者何时完成,然后在消费者中检查该标志以及需要写入的环形缓冲槽的数量。如果生产者已经完成,并且环形缓冲区没有需要写入的插槽,消费者可以终止 这很有效 但是,如果我通过插入睡眠来人为延长制作者所花的时间,消费者不会终止。我相信这是使用信号量的结果 这是我正在使用的代码。请注意,在写入所有插槽后,程序将“挂起”。生产者终止,但消费者“挂起” 如有任何关于有序终止两者的建议,将不

目前,我有一个由生产者和消费者线程运行的RingBuffer

在寻找一种有序终止它们的方法时,我想我应该使用一个标志来指示生产者何时完成,然后在消费者中检查该标志以及需要写入的环形缓冲槽的数量。如果生产者已经完成,并且环形缓冲区没有需要写入的插槽,消费者可以终止

这很有效

但是,如果我通过插入睡眠来人为延长制作者所花的时间,消费者不会终止。我相信这是使用信号量的结果

这是我正在使用的代码。请注意,在写入所有插槽后,程序将“挂起”。生产者终止,但消费者“挂起”

如有任何关于有序终止两者的建议,将不胜感激

编辑-使用Henk建议的队列更新代码+1000分给第一个人,建议终止使用者/生产者线程的更好方法,而不是知道正在处理的项目的确切数量返回null/nothing等值,指示队列中不存在更多项目(虽然这并不意味着它们还没有生产出来。)

编辑-我相信我已经找到了答案。只需将null或nothing传递给RingBuffer。为每个消费者排队,并捕获消费者中的null或nothing对象以终止它。希望有人发现这很有用

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,我将尝试一下。