参考:https://blog.csdn.net/naruto_ahu/article/details/8672376
1、单生产者和单消费者
缓存绑定问题,两个进程:生产者和消费者,一个固定大小的缓存。
生产者的工作就是制造一段数据,放进缓存,如此反复;消费者则一次消费一段数据(将其从缓存中移除),问题的核心就是要保证不让生产者在缓存还是满的时候仍要向缓存写数据,不让消费者试图从空的缓存中取出数据。
解决方案:
如果缓存满了,生产者就去睡觉,消费者从缓存中取走数据后叫醒生产者,让他再次将缓存填满,如果缓存为空,消费者去睡觉,等到生产者将数据写入缓存后就叫醒消费者,通过使用“进程间通信”解决这个问题------信号标,但是不完善的解决方案会造成“死锁”,即两个进程都在“睡觉”,等待对方来“唤醒”
“信号标法”-------解决唤醒问题,使用两个信号标,fillCount和emptyCount来解决问题,新的数据添加到缓存中后,fillCount在增加,而emptyCount在减少,如果生产者试图在emptyCount为0减少其值,生产者就会被“催眠”,下一轮有数据被消费掉时,emptyCount就会增加,生产者被“唤醒”
semaphore fillCount = 0
semaphore emptyCount = BUFFER_SIZE
procedure producer() {
while (true) {
item = produceItem()
down(emptyCount)
putItemIntoBuffer(item)
up(fillCount)
}
}
procedure consumer() {
while (true) {
down(fillCount)
item = removeItemFromBuffer()
up(emptyCount)
consumeItem(item)
}
}
2、多消费者和多生产者
上述解决方案只适用于单消费者和单生产者,在多个生产者和多个消费者出现的情况下就会造成拥堵,会导致两个或多个进程同时向一个磁道写入或读出数据,可能发生如下情况:
(1)两个生产者为emptyCount减值
(2)一个生产者判断缓存中有可用磁道,另一个生产者也判断有可用磁道(此时只有1个可用磁道了)
(3)两个生产者同时向同一个磁道写入数据
为了解决如上问题,需要确保同一时刻,只有一个生产者在生产数据,需要引入“互斥信号标”的关键扇区,使用一个叫mutex二位信号标,因为一个二位信号标的值只能是1或0,只有一个进程能执行加或者减
semaphore mutex = 1
semaphore fillCount = 0
semaphore emptyCount = BUFFER_SIZE
procedure producer() {
while (true) {
item = produceItem()
down(emptyCount)
down(mutex)
putItemIntoBuffer(item)
up(mutex)
up(fillCount)
}
up(fillCount) //the consumer may not finish before the producer.
}
procedure consumer() {
while (true) {
down(fillCount)
down(mutex)
item = removeItemFromBuffer()
up(mutex)
up(emptyCount)
consumeItem(item)
}
}