操作系统作业-并发性:互斥和同步
1. 什么是临界资源、临界区,临界区的使用原则有哪些?
进程间在竞争控制中会面临互斥问题。假设两个或者更多的进程需要访问一个不可共享的资源,如打印机,在进程的执行过程中,每个进程都给该I/O设备发命令,接收状态信息,发送数据和接受数据,则这类资源称为临界资源。
使用临界资源的那部分程序称为程序的临界区。
临界区主要解决的是互斥问题,互斥问题的要求可总结为:空闲让进,忙则等待,有限等待,让权等待。同时,这也是对于临界区使用的原则,具体内容如下:
- 实施强制互斥:在与相同资源或共享对象的临界区有关的所有进程中,一次只允许一个进程进入临界区;
- 一个在非临界区停止的进程不能干涉其他进程
- 绝不允许出现需要访问临界区的进程被无限延迟的情况,即不会死锁或饥饿;
- 没有进程在临界区中时,任何需要进入临界区的进程必须能够立即进入;
- 对相关进程的执行速度和处理器的数量没有任何要求和限制;
- 一个进程驻留在临界区中的时间必须是有限的。
2. 简述信号量的含义及作用。
信号量的含义:用于进程间传递信号的一个整数值。在信号量上只可进程初始化、递减和递增这三种操作,且操作都是原子操作。
信号量的作用:解决互斥问题,在两个或多个进程通过信号量进行合作时,可以强迫一个进程在某个位置停止,直到它接收到一个特定的信号。信号量的三种操作中,递减操作用于阻塞一个进程,递增操作用于解除一个进程的阻塞。
3. 请用P、V操作描述下列过程
//司机
void driver(){
while (true) {
semWait(door); //收到关门信息,开始开车
/*正常运行*/;
semSignal(stop); //到站停,释放门这个资源
}
}
//售票员
void conductor(){
while (true){
semSignal(door); //发送信号:关门
/*售票*/;
semWait(stop); //接收司机释放的到站停信息
/*开门*/;
}
}
4. 图书馆有N个座位,一张登记表,要求(1)阅读者进入时登记,取得座位号;(2)出来时注销。请用P、V操作描述一个读者的使用过程。
//图书馆没有座位就等待
semaphore s = N , M = 1; //s可用座位,M=1表示无人在使用
void lib1(){
while(true){
semWait(s);
semWait(M);
/*登记*/;
semSignal(M);
/*阅读*/;
semWait(M);
/*注销*/;
semSignal(M);
semSignal(s);
}
}
//图书馆没有座位就离开
int COUNT = 100;
semaphore M = 1;
void lib2(){
semWait(M);
if(COUNT == 0){
semSignal(M);
return;
}
COUNT = COUNT - 1;
/*登记*/;
semSignal(M);
/*阅读*/;
semWait(M);
/*注销*/;
semSignal(M);
semWait(M);
COUNT = COUNT + 1;
semSignal(M);
return;
}
5. 4个并发执行的进程P1、P2、P3和P4合作解决数据计算问题:Y(i)=X(i)2+X(i)3.
(1) P1不断产生随机数并放入到缓冲区A中;
(2) P2、P3分别读取缓冲区A中的数据并计算其平方值、立方值,然后分别放入缓冲区B、C中;
(3) P4读取缓冲区B、C中的数据,将其相加,并输出;
(4) 缓冲区A、B、C的容量为1。
semaphore emptyA = 1,emptyB = 1,emptyC = 1; //初始A,B,C为空
semaphore fullA = 0,fullB = 0,fullC = 0 , readA = 0;//readA=0,不读
void p1(){
while(true){
/*产生随机数*/;
semWait(emptyA); //接收到A空的信号
/*将随机数放入缓冲区A*/;
semSignal(fullA); //写入后A为满
}
}
void p2(){
while(true){
semWait(fullA); //接收到A已写入
/*从A取数据*/;
semSignal(readA); //发信号让B读A
/*计算平方值*/;
semWait(empytB) //接收到B为空的信号
/*平方值放入缓存区B*/;
semSignal(fullB); //写入B
}
}
void p3(){
while(true){
semWait(readA); //等p2读了数据,p3接收到readA信号再读
/*从A取数据*/;
semSignal(emptyA); //释放A的资源
/*计算立方值*/;
semWait(emptyC); //接收到C为空的信号
/*立方值放入缓存区C*/;
semSignal(fullC); //写入C
}
}
void p4(){
while(true){
semWait(fullB); //接收到B满的信号
/*取缓冲区B数据*/;
semSignal(emptyB); //取出B,发送empytB信号
semWait(fullC); //接收到C满的信号
/*取缓冲区C数据*/;
semSignal(emptyC); //取出C,发出emptyC的信号
/*计算B+C的数据*/;
/*数据B+C 输出*/;
}
}
6. 桌上有一空盘,最多允许存放一只水果。爸爸可向盘中放一个苹果或放一个桔子;儿子专等吃盘中的桔子,女儿专等吃苹果。用P、V操作实现爸爸、儿子、女儿三个并发进程的同步。
semaphore P=1;
int plate = 0; //plate=0时,盘子为空
int put = 0; //put=0 放桔子 put=1 放苹果
void father(){
while(true)
if(plate == 0){ //如果盘子为空
semWait(P); //得到盘子的使用权
if (put == 0){ //放桔子
semSignal(S0); //释放专吃桔子的盘子使用权
}
else{ //放苹果
semSignal(S1); //释放专吃苹果的盘子使用权
}
}
else{
return;
}
}
void son(){
while(true){
semWait(S0); //等到盘子放桔子的信号
/*从盘中拿桔子*/;
semSignal(P); //释放盘子的使用权
/*吃桔子*/;
}
}
void daughter(){
while(true){
semWait(S1); //等到盘子放苹果的信号
/*从盘中拿苹果*/;
semSignal(P); //释放盘子的使用权
/*吃苹果*/;
}
}
7. 用P、V原语实现东西向单行道上车辆的正确行驶,要求:(1)当有车自东向西方向(或自西向东方向)行驶,另一方向上的车辆须等待;(2)同一方向上的车可以连续通过;(3)当某一方向上已经没有车辆在单行道上行驶时,另一方向上的车辆即可以进入单行道。
int e_wcount, w_ecount;
semaphore x1 = 1,x2 = 0,wsem = 1;
void e_w(){
while ((true){
semWait(x1);
e_wcount++;
if(e_wcount == 1){
semWait(wsem);
}
semSignal(x1);
/*通过*/;
semWait(x1);
e_wcount--;
if (e_wcount == 0){
semSignal(wsem);
}
semSignal(x1);
}
}
void w_e (){
while (true){
semWait(x2);
w_ecount++;
if (w_ecount == 1){
semWait(wsem);
}
semSignal(x2);
/*通过*/;
semWait(x2);
w_ecount--;
if (w_ecount == 0){
semSignal(wsem);
}
semSignal(x2);
}
}
8. 某寺庙,有小、老和尚若干,有一水缸,由小和尚提入水缸供老和尚饮用。水缸可容10桶水,水取自同一井中。水井径窄,每次只能容一个水桶取水,水桶总数为3个。每次入水、取水仅为1桶,且不可同时进行。试给出有关老和尚从缸取水和小和尚打水、入水的算法描述。(感觉这个题,描述得很有问题,不好)
int tong = 3,vatWater = 10,haveWater=0;
void little(){
while(true){
semWait(vatWater); //看缸里水有多少
semWait(tong); //等待空闲的桶
semWait(s1); //取打水使用权
/*打水*/;
semSignal(s1); //释放打水使用权
semWait(s2); //取入水缸使用权(入水)
/*入水*/;
semWait(s2); //释放水缸使用权
semSignal(tong); //释放桶的使用权
semSignal(haveWater); //打了水了
}
}
void old(){
while(true){
semWait(haveWater); //呗小和尚告知有水了
semWait(tong); //有桶了
semWait(s1) //取水缸使用权
/*取水*/;
semSignal(s1); //释放水缸使用权
semSignal(tong); //释放桶的使用权
semSignal(vatWater); //缸里的水被打了,告知小和尚
}
}
9. 参考读者优先问题的代码,分析读者进程中的if (readcount==1) P(wsem) 是否可以放到紧跟的V(x)语句后?给出可以或不可以的理由。类似的,分析if (readcount==0) V(wsem) 是否可以放到紧跟的V(x)语句后?
if (readcount==1) P(wsem)不能放到紧跟的V(x)语句后,因为P(x)和V(x)保证了再这两条语句中间,不能有其他的进程来更改readcount的值。
如果将if (readcount==1) P(wsem)放到紧跟的V(x)语句后,这期间为非原子操作,readcount的值可能被另一个进程更改为0,从而造成错误。
if (readcount==0) V(wsem)不能放到紧跟的V(x)语句后,理由跟上一问一样。
如果将if (readcount==0) V(wsem)放到紧跟的V(x)语句后,这两条语句之间为非原子操作,从而导致readcount的值可能被其他进程修改为1,导致出错。