1.PV信号量的分类
1) 普通型信号量
wait(S) {
// P(S)
while(S <= 0);
S = S - 1;
}
signal(S) {
// V(S)
S = S + 1;
}
没有实现让权等待!让进程处于忙等状态!
2) 记录型信号量
void wait(S) {
//一定要注意:先改变value,然后再去做block或者wakeup操作
S.value--;
if(S.value < 0) {
/不带等号,说明减之前S.value = 0,没有资源了/
add this process to S.L;
block(S.L);
}
void signal(S) {
//一定要注意:先改变value,然后再去做block或者wakeup操作
S.value++;
if(S.value <= 0) {
/*加之前S.value 最大为-1,反正是个负数,说明需要将它wakeup*/
remove this process from S.L;
wakeup(S.L);
}
}
//记录型信号量实现了让权等待!
2.经典模型
1)前驱图
-->进程的同步,前一个结点释放后V,后面的结点去P。
![](https://img-blog.csdnimg.cn/img_convert/6a37874a5a82aa0ac782da24e5310215.png)
semaphore a1, a2, b1, b2, c, d, e = 0;
Process S1() {
....;
v(a1);
V(a2);
}
Process S2() {
P(a1);
....;
V(b1);
}
....
Process S6() {
P(d);
p(e);
....;
}
2)生产者消费者问题
单生产者单消费者问题
![](https://img-blog.csdnimg.cn/img_convert/1f814a5b29b1b0787674fe2e20669b0d.png)
/*设缓冲区大小为n*/
semaphore empty = n; //记录空闲缓冲区数量
semaphore full = 0; //记录
semaphore mutex = 1; //实现互斥访问缓冲区
producer() {
while(true) {
//P(mutex) // false,这样申请可能会导致死锁!
produce a product;
P(empty); //获取空闲缓冲区资源
P(mutex); //进入临界区 --- 互斥加紧
add the item to the buffer;
V(mutex);
V(full);
}
}
consumer() {
while(true) {
P(full);
P(mutex);
pull an item from the buffer;
V(mutex);
V(empty);
consume the product;
}
}
多生产者多消费者问题
![](https://img-blog.csdnimg.cn/img_convert/1919404fa60af74a63d6beff776c1c5e.png)
semaphore mutex = 1; //用于实现盘子的互斥访问
semaphore apple = 0; //用于实现爸爸和儿子的同步
semaphore orange = 0;//用于实现母亲和女儿的同步
dad() {
while(true) {
prepare an apple;
P(mutex);
put the apple on the plate;
V(apple); //此处不能释放mutex,dad放苹果和儿子取苹果应该是一个连续的过程!****
}
}
son() {
while(true) {
P(apple);
pull the apple from the plate;
V(mutex);
eat the apple;
}
}
mom() {
while(true) {
prepare an orange;
P(mutex);
put the orange on the plate;
V(orange); //此处不能释放mutex,dad放苹果和儿子取苹果应该是一个连续的过程!****
}
}
daughter() {
while(true) {
P(orange);
pull the orange from the plate;
V(mutex);
eat the orange;
}
}
吸烟者问题
![](https://img-blog.csdnimg.cn/img_convert/74c58fce5c189aea17c0c5a1e67234b2.png)
/*与爸爸妈妈儿子那个问题有区别,三个吸烟者各求所需,如果不是自己需要的原料,就不会去取,所以不需要互斥信号量,只需要同步信号量*/
semaphore offer1 = 0;
semaphore offer2 = 0;
semaphore offer3 = 0;
semaphore finish = 0; //用来判断原料是否被使用
producer() {
while(true) {
int num = random() % 3; //产生0到2的随机数
if(num == 0) {
V(offer1);
}else if(num == 1) {
V(offer2);
}else {
V(offer3);
}
P(finish);
}
}
smoker_i() {
while(true) {
P(offeri);
抽烟i;
V(finish);
}
}
3)读者写者问题
/*没有实现读写公平*/
int cnt = 0; //记录读者的数量
semaphore rw = 1; //用于实现读写互斥
semaphore mutex = 1; //用于更新cnt时的互斥
writer() {
while(true) {
P(rw);
write();
V(rw);
}
}
reader() {
while(true) {
P(mutex);
if(cnt == 0) {
/*第一个读的人*/
P(rw);
}
cnt++;
V(mutex);
read();
P(mutex);
cnt--;
if(cnt == 0) {
/*最后一个读的人*/
V(rw);
}
V(mutex);
}
}
/*上面的算法没有实现读写公平,写操作很容易产生饥饿*/
semaphore w = 1; //用于实现写优先;
semaphore rw = 1;
semaphore mutex = 1;
int cnt = 0;
writer() {
while(true) {
P(w);
P(rw);
write();
V(rw);
V(w);
}
}
reader() {
while(true) {
P(w);
P(mutex);
if(cnt == 0) {
P(rw);
}
cnt++;
V(mutex);
V(w); //在这里释放w,后面不再需要w
read();
P(mutex);
cnt--;
if(cnt == 0) {
/*最后一个读的人*/
V(rw);
}
V(mutex);
}
}
4)哲学家就餐问题
/*进餐取筷子时置mutex,其他人不能动,取完筷子其他人就可以动了*/
semaphore mutex = 1;
semaphore chopstick[5] = {1, 1, 1, 1, 1};
Pi() {
while(true) {
P(mutex);
P(chopstick[i]);
P(chopstick[(i+1)%5]);
V(mutex);
eat;
V(chopstick[i]);
V(chopstick[(i+1)%5]);
think;
}
}
3.王道后面的练习题
![](https://img-blog.csdnimg.cn/img_convert/6986eb104213a21c5c3e3c5f5873a5b6.png)
semaphore mutex = 1; //互斥访问临界区
semaphore empty = N;
semaphore odd = 0;
semaphore even = 0;
P1() {
while(true) {
n = produce();
P(empty);
P(mutex);
put(n);
if(n % 2 == 0) {
V(even);
} else {
V(odd);
}
V(mutex);
}
}
P2() {
while(true) {
P(odd);
P(mutex);
getOdd();
V(mutex);
V(empty);
countOdd();
}
}
...
![](https://img-blog.csdnimg.cn/img_convert/c3dabccfb9540f37bef6ca77220101db.png)
int i = 0, int j = 0; //取号为i,叫号为j
semaphore mutex_i = 1, mutex_j = 1;
consumer(){
while(true){
进入面包店;
P(mutex_i);
取号i;
i++;
V(mutex_i);
等待被叫买面包后离开;
}
}
seller() {
while(true) {
P(mutex_j);
if(i > j) {
叫号j;
j++;
V(mutex_j);
买面包;
}else{
V(mutex_j);
休息;
}
}
}
![](https://img-blog.csdnimg.cn/img_convert/142e4e892721c8580a9c30d2b97cd73b.png)
semaphore vat = 1; //互斥使用水缸;
semaphore well = 1; //互斥使用水井;
semaphore pail = 3; //水桶有3个
semaphore empty = 10;
semaphore full = 0;
smallmonk() {
while(){
P(empty);
P(pail);
P(well);
打水;
V(well);
P(vat);
将水倒入水缸;
V(vat);
V(pail);
V(full);
}
}
bigmonk() {
while(true) {
P(full);
P(pail);
P(vat);
从水缸中取水;
V(vat);
V(empty);
喝水;
V(pail);
}
}
![](https://img-blog.csdnimg.cn/img_convert/72c6e22b3a518d68498fac6bf87c916a.png)
semaphore Sa = n, Sb = n; //超过n时才会暂停,所以此处应该包含n
semaphore emptya = m, emptyb = m;
semaphore fulla = 0, fullb = 0;
semaphore mutex = 1; //互斥的访问一个仓库
StoreA(){
while(true) {
P(emptya);
P(Sa);
P(mutex);
生产一个A并放入仓库;
V(mutex);
V(Sb); //***
V(fulla);
}
}
StoreB(){
while(true) {
P(emptyb);
P(Sb);
P(mutex);
生产一个B并放入仓库;
V(mutex);
V(Sa); //***
V(fullb);
}
}
Composition() {
while(true) {
P(fulla);
P(fullb);
P(mutex);
取出一个A和一个B,组装;
V(mutex);
V(emptya);
V(emptyb);
}
}
![](https://img-blog.csdnimg.cn/img_convert/6520916825d819a8c117e190d1344679.png)
semaphore barber = 0; //用来实现同步
semaphore costomer = 0; //用来实现同步
int count = 0;
semaphore mutex = 1; //实现互斥访问count
Barber() {
while(true) {
P(costomer); //有没有顾客,没有就睡觉;
P(mutex);
count--;
V(mutex);
理发;
V(barber);
}
}
Costomer() {
while(true) {
P(mutex);
if(count < n) {
count++;
V(costomer); //叫barber
P(barber);
V(mutex);
理发;
}else {
V(mutex);
离开;
}
}
}