原创文章,转载请注明出处http://www.cnblogs.com/lihaqwq/p/8645969.html
信号量机制与解题思路
- 信号量机制
P:申请资源 V:访问资源,产生资源 S:大于0时代表当前可用资源,小于0时代表因请求该资源而被阻塞的资源)
有i个生产者,j个消费者,信号量empty的初值为k,信号量full初值为0,信号量mutex为1,共用k个缓冲区。求各信号量的取值范围?
此题帮助很好的理解了p v s的含义
- 解题思路
- 关系的确定:对于某种资源而言,哪些进程是互斥的。哪些进程又存在同步关系。然后通过信号量来实现这些关系,一个关系往往需要一个或者2个信号量来实现。
- 确定临界资源:对于临界资源的操作往往都是 P(mutex); 临界代码;V(mutex)作为一个整体出现
- 需要注意的是:在多进程中为了避免出现拥有资源使用权却没有资源可以使用的死锁情况。必须先对资源信号量进行P操作,然后再对互斥信号量进行P操作
生产者 --消费者
- 对于生产者消费者问题我认为应当把full 与empty都看作两种资源。
- 对于生产者而言,空缓冲区是他的资源
- 对于消费者而言,满缓冲区是他的资源
- 二者相互为对方提供资源,生产时消费的前提
1 semaphore full=0; //满缓冲区数目,也就是可供消费者申请的资源 2 semaphore empty=n; //可供生产者使用的资源 3 semaphore mutex-1; //对缓冲区的互斥访问 4 5 Producer() 6 { 7 while (true) 8 { 9 produce an item put in nextp; 10 P(empty); 11 P(mutex); //占有资源访问权时,保证有资源可以使用 12 将产品放入缓冲池; 13 V(mutex); 14 V(full); 15 } 16 17 } 18 19 Consumer() 20 { 21 while(true) 22 { 23 P(full); 24 P(mutex); 25 取出产品; 26 V(mutex); 27 V(empty) 28 } 29 }
读者--写者
- 任意多個讀者可同时读
- 一次只能有写者向文件中写(写进程互斥)
- 如果写者正在进行操作,禁止任何进程对文件进行操作
- 读者优先
为了保证读者优先可以设置readcount 或者 标记是否可写的信号量 writable
1 semaphore rmutex=1; //对信号量readcount的互斥访问 2 semaphore mutex=1;//对数据区的写互斥 3 int readcount=0; 4 5 Reader() 6 { 7 while(true){ 8 P(rmutex); //申请对readcount的使用 9 if(readcount==0) P(mutex);//若是第一个读者,则申请mutex资源 保证读者优先 10 readcount++; 11 V(rmutex); 12 读操作; 13 P(rmutex); 14 readcount--; 15 if(readcount==0) V(mutex);//若没有读者,则允许进行写操作 16 V(rmutex); 17 } 18 } 19 20 Writer() 21 { 22 while(true){ 23 P(mutex); 24 写操作; 25 V(mutex); 26 } 27 }
- 写者优先
即是说只要有写者到达或者申请临界资源,读者无限期等待。为实现这一插队功能,设置信号量 readable
在写者申请mutex之前申请 readable信号量。没有写者等待之后再释放readable信号量
p(readable)在p(rmutex)之前申请,是写者优先实现写着插队的关键。写者一旦成功申请readable,后续到达的写者就不需要申请,且读者需要不断的申请readable然后释放readable,就给了写者插队的机会。
信号量mutex在读者中被占用,并不影响写者插队。因为那可以看作正在执行状态的进程占用mutex,而就绪(等待)队列中读者并不影响写者插队
semaphore rmutex=1; semaphore wmutex=1;//分别对readcount和writecount的互斥访问 semaphore mutex=1; //互斥访问数据区 int readcount=0,writecount=0; reader() { while(true) { P(readable); //检查是否有写者写入ing P(rmutex); //申请对readcount的使用 if(readcount==0) P(mutex);//若是第一个读者,则申请mutex资源 保证读者优先 readcount++; V(rmutex); V(readable); //释放readable,允许其他读者或写者使用 读操作; P(rmutex); readcount--; if(readcount==0) V(mutex); V(rmutex); } } writer() { { P(wmutex); if(writecount==0) P(readable);//保证写者插队的关键 占住资源不放只需要等待当前读者全部完成操作即可插队 writecount++; V(wmutex); P(mutex) 写操作; V(mutex); P(wmutex); writecount--; if(writecount==0) V(readable); V(wmutex); } }
- 理发师问题
理发店有一位理发师,一把理发椅,n个供顾客等待用的凳子。理发流程:第一位顾客到来时,叫醒理发师,然后坐下理发(即是说占用理发椅)
若理发师正在理发,则坐下等待,若没有空凳子则离开。
思路1:按流程整理出资源和进程
思路2:把所有的椅子看成一种资源(可以解读为类似于一个生产者,多个消费者的问题:理发师进程产生finish这个资源 顾客产生ready资源。顾客是理发进程的前提)
int chairs =n+1; semaphore mutex=1;//chairs的互斥信号量 semaphore finish=1;//已完成理发,处于空闲状态 semaphore ready=0;//有顾客在等待否 取值范围0--(1+n) barber() { while(true) { P(ready); 理发: P(mutex); chairs++; V(mutex); V(finish); } } constomer() { P(mutex); if(chairs>0) { chairs--; V(mutex); V(ready); P(finish);//申请理发,若无资源则阻塞 } else V(mutex); }
注:
- 无论是同步还是互斥P ,V都是成对出现的
- 互斥的信号量通常为1,代表资源数为1,同时只能供一个进程访问