本文共 5787 字,大约阅读时间需要 19 分钟。
mutex
为互斥信号量
,用于控制互斥访问缓冲池
,初值设为 1;信号量 full 用于记录当前缓冲池中的“满”缓冲区数
,初值为 0;信号量 empty 用于记录当前缓冲池中“空”的缓冲区数,初值为 n;seamphore mutex=1; //临界区互斥信号量 seamphore empty=n; //空闲缓冲区 seamphore full=0; // 缓冲区初始化为空 producer(){ // 生产者进程 while(1){ produce an item in nextp; // 生产数据 P(empty);(用什么,p一下)// 获取空缓冲区单元 P(mutex);(互斥夹紧) // 进入临界区 add nextp to buffer; (行为)//将数据放入缓冲区 V(mutex);(互斥夹紧) // 离开临界区,释放互斥信号量 V(full);(提供什么,V一下)//满缓冲区数加1 } } consumer(){ //消费者进程 while(1){ P(full); //获取满缓冲区单元 P(mutex); //进入临界区 remove an item from buffer; // 从缓冲区取出数据 V(mutex); // 离开临界区,释放互斥信号量 V(empty); // 空缓冲区数加 1 consume the item; //消费数据 } }
加锁信号量的顺序不能打乱,否则容易出现死锁
。例如 生产者若先执行 P(mutex),再P(empty),消费者先执行P(mutex),再P(full)时,当消费者已将缓冲区放满,而消费者并没有取走产品,即empty=0,当下次仍是生产者进程运行时,由于先执行P(mutex)再P(empty),则会发送阻塞,希望消费者取出产品将其唤醒;轮到消费者进程时,同样先执行P(mutex),但是由于生产者已经封锁mutex信号量,消费者进程因此也阻塞,于是生产者和消费者都会陷入无休止的等待。同理,若消费者将缓冲区已经取空,即负利率=0,下次若还是消费进程执行,那么也会产生类似的死锁。释放信号量的顺序则没有严格要求
。plat
e 表示互斥信号量
,用于确定是否可以往盘子中放水果
,初值为 1 表示允许放入一个;信号量 apple 表示盘中是否还有苹果,初值为 0表示没有不许取;orange 表示盘中是否有橘子,初值同样为 0,orange=1 表示盘子中由橘子允许取。semapore plate=1,apple=0,orange=0; dad(){ while(1){ prepare an apple; P(plate); //互斥向盘中取、放水果 put the apple on the plate; //向盘中放苹果 V(apple); // 允许取苹果 } } mom(){ while(1){ prepare an orange; P(plate); put the orange on the plate; V(orange); } } son(){ while(1){ P(orange); //互斥从盘中取橘子 take an orange from the plate; V(plate); //允许向盘中放、取水果 eat the orange; } } daughter(){ while(1){ P(apple); take an aplle from the plate; V(plate); eat the apple; } }
int count=0; semaphore mutex=1; semaphore rw=1; writer(){ while(1){ P(rw); // 互斥访问共享文件 writing V(rw); // 释放共享文件 } } reader(){ while(1){ P(mutex); // 互斥访问 count 变量 if(count==0) // 当第一个读进程读共享文件时 P(rw) // 阻止写进程 count++; V(mutex); // 释放互斥变量 count reading; P(mutex); count--; if(count==0) // 当最后一个读进程读完共享文件 V(rw); // 允许写进程写 V(mutex); } }
此种方式下,可能导致写进程长时间等待甚至出现“饿死”的情况
。改变上面这种读进程优先,让写进程优先,需要再增加一个信号量,并在上面的 writer() 和 reader() 函数中各增加一对PV操作
,如下:``` int count=0; semaphore mutex=1; semaphore rw=1; semaphore w=1; // 实现写者优先 writer(){ while(1){ P(w); // 在无写进程请求时进入 P(rw); // 互斥访问共享文件 writing V(rw); // 释放共享文件 V(w); // 恢复对共享文件的访问 } } reader(){ while(1){ P(w); P(mutex); // 互斥访问 count 变量 if(count==0) // 当第一个读进程读共享文件时 P(rw) // 阻止写进程 count++; V(mutex); // 释放互斥变量 count V(w); reading; P(mutex); count--; if(count==0) // 当最后一个读进程读完共享文件 V(rw); // 允许写进程写 V(mutex); } }```
此种算法又叫做读写公平法
。``` semaphore chopstick[5]={1,1,1,1,1}; Pi(){ do{ P(chopstick[i]); //取左边筷子 P(chopstick[(i+1)%5]);// 取右边筷子 eat; V(chopstick[i]); //放回左边筷子 V(chopstick[(i+1)%5]);// 放回右边筷子 think; }while(1); }```
此算法存在的问题就是,当5名哲学家都想要进餐并分别拿起左边的筷子时,所有的筷子将被拿光,等到他们再想拿起右边的筷子时,就会发生全被阻塞,出现死锁
。若要避免此种情况,可以增加限制条件,如至多允许4名哲学家同时进餐;仅当一名哲学家左右两边筷子都可以用时,才允许他抓起筷子;对哲学家顺序编号,奇数号哲学家先拿起左边筷子,然后拿起右边的,而偶数哲学家相反。``` semaphore chopstick[5]={1,1,1,1,1}; semaphore mutex=1; Pi(){ do{ P(mutex); // 在取筷子前获得互斥量 P(chopstick[i]); //取左边筷子 P(chopstick[(i+1)%5]);// 取右边筷子 V(mutex); // 释放取筷子的信号量 eat; V(chopstick[i]); //放回左边筷子 V(chopstick[(i+1)%5]);// 放回右边筷子 think; }while(1); }```
int random; // 存储随机数 semaphore offer1=0; semaphore offer2=0; semaphore offer3=0; semaphore finish=0; process P1(){ while(1){ random=a random num; random=random%3; if(random==0) V(offer1); // 提供烟草和纸 else if(random==1) V(offer2); // 提供烟草和胶水 else V(offer3); //提供纸和胶水 put on ; // 将材料放在桌子上 P(finish); } } process P2(){ while(1){ P(offer3); working; // 拿起纸和胶水,卷成烟,抽掉 V(finish); } } process P3(){ while(1){ P(offer2); working; // 拿起烟草和胶水,卷成烟,抽掉 V(finish); } } process P4(){ while(1){ P(offer1); working; // 拿起纸和烟草,卷成烟,抽掉 V(finish); } }
转载地址:http://gmqgn.baihongyu.com/