本文共 3614 字,大约阅读时间需要 12 分钟。
铺垫是关于使用mutex作为锁实现的核心,那就是原子操作P(wait)和V(singal)的作用及含义。
- P是操作就是使得信号量Semophore的数量减一,当然了前提是信号量的大小是大于0的,如果小于等于0,此进程就会阻塞在该信号量的等待队列上面,只有等待来自另外的进程的唤醒信息来唤醒它。 - V操作就是使得信号量的数量加一,而在此处信号量的如果是小于0的,那么这个数的值就是该信号量的等待队列的进程的数目。在进行对信号量的操作的核心就是,只有P和V操作可以对信号量进行加减,其他操作没有此权限。
首先是考虑生产者和消费者只有一对一,且仓库的容量也只有一的状况:
生产者将生产的产品放入到仓库中。那么我们不难想象只有在仓库中有产品的时候,消费者才能消费;只有仓库存在空位的时候,生产者才能将生产的产品放入到仓库。此时,对于生产者而言仓库为empty就是它的资源,对于消费者而言,仓库为full就是它的资源。//对于生产者while(true){ //生产产品 p(empty); //将产品放入到仓库 v(full);}--------------------------------------------------------------------------------------//对于消费者while(true){ p(full); //消费产品 v(empty);}
现在考虑第二个阶段,那就是现实中仓库的容量n一般来说都是远远大于1的,那么情况会变成什么样呢?
经过老师指导,使用环形缓冲原理就可以实现对仓库的良好的访问,而且效率也很高。//对于生产者 i = 0; while(true){ //生产产品 p(empty); //将产品放入到仓库 i = (i+1) % n ; v(full); } --------------------------------------------------------------------------------------//对于消费者 j = 0; while(true){ p(full); //消费产品 j = (j + 1 ) % n ; v(empty); }
/对于生产者 i = 0; while(true){ //生产产品 p(empty); p(mutex); //将产品放入到仓库 i = (i+1) % n ; v(mutex); v(full); } --------------------------------------------------------------------------------------//对于消费者 j = 0; while(true){ p(full); p(mutex); //消费产品 j = (j + 1 ) % n ; v(mutex); v(empty); }
对于这个经典的问题,我们需要了解的是读者与写者都是对于同一个Shared Data进行访问的,所以就有可能出现下面的几种情况。
1、读操作可以同时进行(R-R)2、读操作和写操作不可以同时进行(R-W,互斥)3、写操作和写操作不可以同时进行(W-W,互斥)
因此,我们需要谨慎的进行处理了。
- 下面是第一种我们可能想到的最朴素的想法。那就是加锁,不论三七二十一,双方都进行加锁,这样就不会出现上面的2,3问题了。但是却违背了1的问题,因为RR是可以并发的。//对于读者 while(true){ p(mutex); //读取数据 v(mutex); }-----------------------------------------------------------------------------------------------//对于写者 while(true){ p(mutex); //写入数据 v(mutex); }
while (true) { P(r_mutex); r_cnt++; if(r_cnt==1) P(mutex); V(r_mutex); read(); P(r_mutex); r_cnt- -; if(r_cnt==0) V(mutex); V(r_mutex); }
其中,里面的核心处理就在于
P(r_mutex); r_cnt++; if(r_cnt==1) P(mutex); V(r_mutex);
是对于r_cnt数量的修改时互斥的保证。实现的功能就是在所有读者中只允许有一个读者获得锁,这样便可以满足1,2,3的要求了。但是这并不是最完美的解决方案,因为有可能读者数量会很大很大,而写者根本没时间写入数据,导致“死等”的情况出现。因此我们还得进行进一步的改进措施。
//核心就在于rw_mutex信号量的掌控上 //读者 while (true) { P(rw_mutex); P(r_mutex); r_cnt++; if(r_cnt==1) P(mutex); V(r_mutex); V(rw_mutex); read(); P(r_mutex); r_cnt- -; if(r_cnt==0) V(mutex); V(r_mutex); } //写者 while (true) { P(rw_mutex); P(mutex); write(); V(mutex); V(rw_mutex); }
do{ wait ( chopstick[i] ); wait ( chopStick[ (i + 1) % 5] ); // eat signal ( chopstick[i] ); signal (chopstick[ (i + 1) % 5] ); // think } while (TRUE);
但是这样会存在一个问题,那就是“死锁”,比如每个哲学家都拿到了一只筷子,那么整个代码就会处于Deadlock的处境。那么怎样才能解决这个问题呢?
操作系统课上,胡燕老师幽默的讲课风格让我有了很大的热情来研究这里面的复杂的学问,虽然自己目前而言水平仍然很差,但是我从中收获到了很多。感谢老师!
转载地址:http://tzfkm.baihongyu.com/