i. 生产者生产一条数据
1. 首先查看缓冲区能否放入数据,有没有空的位置,如果有往下执行,否则说明缓冲区全
满了,消费者可能干什么去了没有来取数据,所以生产者阻塞等待资源,当一定的时候被唤醒(有空的了)。在此处,生产者如果发现缓冲区已经满了,生产者阻塞在此处。
2. 之后查看临界区是否可用(有没有进程在临界区),否则必须等待使用权,当使用临界资源的进程退出唤醒之。假设3个生产者都已经申请到资源,但是到此处时,只能有一个生产者可以进入,所以又要被阻塞一次。
3. 存入一条数据
4. 退出临界区,归还使用权
5. 数据单元+1,唤醒消费者。
ii. 消费者消费一条数据
1. 首先查看有数据单元,如果有执行,否则消费者阻塞等待资源,直到被生产者唤醒(信号?)
2. 查看临界区是否可用,如果可用执行,否则阻塞等待使用权。
3. 从缓冲区取一条数据。
4. 归还临界区使用权
5. 空单元+1,唤醒一个生产者(数据单元-1,生产者可以生产了)
6. 消费数据
const int buffersize = 10; //缓冲区大小 semaphore s = 1; //互斥信号量,初始化为1 semaphore n = 0; //资源信号量,数据单元,初始化为0 semaphore e = buffersize //资源信号量,空存储单元
void producer() { while(true) { produce(); //生产一条数据 wait(e); //i.1,查看缓冲层是否可用 wait(s); //i.2,查看临界区是否可用 dosomething() //i.3,存入一条数据 signal(s); //i.4,退出缓冲区,归还使用权。 signal(n); //i.5,数据单位+1,唤醒消费者 } }
void consumer() { while(true) { wait(n); //ii.1查看缓冲区是否可用 wait(s); //ii.2查看临界区是否可用 dosomething(); //ii.3取一条数据 signal(s); //ii.4归还临界区使用权 signal(e); //ii.5空单元+1,唤醒生产者 consume(); //消费数据 } } |
七 读者写者问题
1. 问题描述及满足的条件
l 该问题为多个进程访问一个共享数据区建立的一个通用模型,其中若干读进程只能读数据,若干写进程只能写数据。
l 允许多个读者进程可以同时读数据。
l 不允许多个写者同时写数据,只能互斥写数据。
l 若有写者进程正在写数据,则不允许读者进程读数据。
2. 如何控制读者和写者问题
l 如果采用生产者/消费者问题解决方法,严格互斥任何读者和写者进程,可以保证数据更新操作的正确性。
l 但是对于若干读进程,严格互斥,将影响效率,应该让读者同时读数据。
l 如果一个写者进程正在修改数据,别的写者及任何读者都不难访问该数据。
3. 读者优先
l 当一个读者正在读数据,允许其他读者进入。
l 现在假设一个写者到来,由于写操作是排他的,需要阻塞等待,如果一直都有新的读者陆续到来,写者的写操作将被严重推迟。
这种方法称为“读者优先”,一旦读者正在读数据,允许多个读者同时进入读数据,只
有当全部读者退出,才允许写者进入写数据,对写者不公平.
int readcount = 0; //读者个数 semaphore wsem = 1; //互斥信号量,初始化为1,互斥读者和写者 semaphore x = 1; //互斥修改readcount变量 void read() { while(true) { ///x:读者互斥修改readcount这个变量 wait(x); if(++readcount == 1) wait(wsem); signal(x); /// readData(); //读数据
wait(x); if(--readcount == 0) signal(wsem); signal(x); } }
void write() { while(true) { wait(wsem); writeData(); signal(s); } } |
4. 写者优先
l 为了防止“读者优先”可能导致写者饥饿,可以考虑写者优先。
l 即,当共享数据区被读者占用,后续紧邻到达的读者可以继续进入,若这时有一个写者到来且阻塞等待,则写者后面到来的若干读者全部阻塞。
l 这种方案解决写者饥饿问题,但降低了并发程度使系统性能较差。
int readcount = 0; //读者个数 int writecount = 0; //写者个数 semaphore wsem = 1; //写者信号量,互斥写者 semaphore rsem = 1; //读者信号量,互斥读者 semaphore x = 1; //互斥修改readcount变量 semaphore y = 1; //互斥修改writecount变量 semaphore z = 1; //
void read() { while(true) { wait(z); //不让读者排成长队 wait(rsem); wait(x); if(++readcount == 1) wait(wsem); signal(x); signal(rsem); signal(z); /// readData(); //读数据
wait(x); if(--readcount == 0) signal(wsem); signal(x); } }
void write() { while(true) { wait(y); //互斥 if(++writecount == 1) wait(rsem); //阻塞读者 signal(y);
wait(wsem); //写者写数据 writeData(); signal(wsem);
wait(y); if(--writecount == 0) signal(rsem); signal(y); signal(s); } } |