我有一个有 4 个线程的应用程序。 (GUI、 Controller 、生产者、消费者)
GUI 的含义是不言自明的。
Controller 在进行一些初始设置后启动生产者和消费者线程。
生产者创建项目并将它们放置在“环形缓冲区”的空闲槽中
消费者从“环形缓冲区”中获取项目并将它们写入磁盘。
生产者创造元素的速度比消费者高得多。
消费者是 IO 密集型且受 IO 限制的。
目前我正在检查每个环形缓冲区槽中的变量以确定是否可以写入它。
if Slot.Free then Write Slot.Data To Disk end if
我没有使用锁/同步锁,而是只是读取/写入插槽的“自由”变量的值。我不认为这是正确的,即使它是 volatile 读/写。有没有更好的方法来读/写这个变量?该变量的类型为“整数”,并且为 0 或 1。
请您参考如下方法:
您提到使用环形缓冲区,但(正确实现的)环形缓冲区将能够确定它是否已满,而无需检查其所有元素,从而无需在每个插槽中使用 bool 值。
我不习惯 VB.NET,但这应该是环形缓冲区的一个工作(如果粗略)实现,当相应的写入/读取操作已满/空时,该缓冲区会阻塞。
Friend Class RingBuffer(Of T)
Private _slots() As T
Private _head As Integer
Private _tail As Integer
Private _readableSlots As Semaphore
Private _readLock As Object
Private _writableSlots As Semaphore
Private _writeLock As Object
Public Sub New(ByVal size As Integer)
ReDim _slots(size - 1)
_head = 0
_tail = 0
_readLock = New Object
_writeLock = New Object
_readableSlots = New Semaphore(0, size)
_writableSlots = New Semaphore(size, size)
End Sub
Public Function Dequeue() As T
Dim item As T
_readableSlots.WaitOne()
SyncLock _readLock
item = _slots(_head)
_head = (_head + 1) Mod _slots.Length
End SyncLock
_writableSlots.Release()
Return item
End Function
Public Sub Enqueue(ByVal item As T)
_writableSlots.WaitOne()
SyncLock _writeLock
_slots(_tail) = item
_tail = (_tail + 1) Mod _slots.Length
End SyncLock
_readableSlots.Release()
End Sub
End Class
一旦你有了这个,你的生产者和消费者就会变得非常愚蠢:)但是,如果你有多个消费者,则不能完全保证项目按顺序处理:
Private _buffer As RingBuffer(Of Integer) = New RingBuffer(Of Integer)(5)
Private Sub Producer()
Dim i As Integer = 0
Do While True
_buffer.Enqueue(i)
i = i + 1
Loop
End Sub
Private Sub Consumer()
Do While True
Debug.WriteLine(("Consumer A: " & _buffer.Dequeue))
Thread.Sleep(1000)
Loop
End Sub