生产消费问题描述
有一个或多个生产者产生数据,并放到buffer,
一个消费者一次取一条数据
一次只允许一个生产者或消费者进入buffer
buffer不能并行操作(互斥)
生产者不能向非空buffer写数据,消费者不能取空buffer数据(同步)
生产消费者解决方案
有一群生产者进程在生产产品,并将这些产品提供给消费者进程去消费.为使生产者进程与消费者进程能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区中;消费者进程可以从一个缓冲区中取走产品去消费。
问题的解?
伪代码实现
items代表缓冲区已经使用的资源数,spaces代表缓冲区可用资源数
mutex代表互斥锁
buf[N] 代表缓冲区,其内容类型为item
in、out代表第一个资源和最后一个资源
var items = 0, space = N, mutex = 1;
var in = 0, out = 0;
item buf[N] = { NULL };
producer {
while( true ) {
wait( space ); // 等待缓冲区有空闲位置, 在使用PV操作时,条件变量需要在互斥锁之前
wait( mutex ); // 保证在product时不会有其他进程访问缓冲区
// product
buf.push( item, in ); // 将新资源放到buf[in]位置
in = ( in + 1 ) % N;
signal( mutex ); // 唤醒的顺序可以不同
signal( items ); // 通知consumer缓冲区有资源可以取走
}
}
consumer {
while( true ) {
wait( items ); // 等待缓冲区有资源可以使用
wait( mutex ); // 保证在consume时不会有其他进程访问缓冲区
// consume
buf.pop( out ); // 将buf[out]位置的的资源取走
out = ( out + 1 ) % N;
signal( mutex ); // 唤醒的顺序可以不同
signal( space ); // 通知缓冲区有空闲位置
}
}
不能将线程里两个wait的顺序调换否则会出现死锁。例如(调换后),将consumer的两个wait调换,在producer发出signal信号后,如果producer线程此时再次获得运行机会,执行完了wait(space),此时,另一个consumer线程获得运行机会,执行了 wait(mutex) ,如果此时缓冲区为空,那么consumer将会阻塞在wait(items),而producer也会因为无法获得锁的所有权所以阻塞在wait(mutex),这样两个线程都在阻塞,也就造成了死锁。
读写问题
有一个共享的数据对象:
允许多个读者进程同时读;
一次只允许一个写者进程写;当一个写者正在写时,不允许其他任何读者或写者同时访问该共享对象。
读者优先
当至少已有一个读者正在读时,随后的读者直接进入,开始读数据对象,但写者将等待。
但一个写者正在写时,随后到来的读者和写者都等待。
信号量的设置:
一次只能让一个写者或一堆读者访问数据。
设一互斥信号量wsem,初值为1。
正在读数据的读者数目由全局变量readcount表示(初值=0),它被多个读者互斥访问。
(第1个读者需对数据加锁,最后1个读者对数据解锁)
为readcount设一互斥信号量x,初值为1。
void reader(){
while(true){
semWait(x);
readcount++;
if(readcount == 1)
semWait(wsem);
semSignal(x);
/*读数据对象*/
semWait(x);
readcount--;
if(readcount == 0)
semSignal(wsem);
semSignal(x);
}
}
void writer(){
while(true){
semWait(wsem);
/*写数据对象*/
semSignal(wsem);
}
}
读者操作类似于去图书馆看书,有一个阿姨在门口登记一样,登记的时候是互斥的,进去一个就加一,同样出去也是一样的操作。