信号量编程(模板)
试解释为什么在单处理器系统的用户进程中通过屏蔽中断来实现同步是不合理的?
如果用户进程具有屏蔽中断的功能,那么它可以同样屏蔽计时器,没有时钟中断则分派程序无法进行,进程会无限执行
试解释为什么在多处理器系统中无法通过屏蔽中断来实现同步
屏蔽中断仅仅阻止其他进程在被屏蔽了中断的处理器上运行,其他进程可能在其他处理器上运行。
先记住wait()
和signal()
的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 wait(semaphore *S) { S->value--; if (S->value < 0 ) { add this process to S->list ; block(); } } signal(semaphore *S) { S->value++; if (S->value <= 0 ) { remove a process P from S->list ; wakeup(P); } }
经典同步问题
有限缓冲区——生产者、消费者问题
进程互斥 中的生产者-消费者问题可以通过三个信号量解决
二进制信号量mutex
保证了对缓冲区访问的互斥
计数信号量empty
和full
表示缓冲区中空余数量和已有数据数量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 do { wait(empty); wait(mutex); signal(mutex); signal(empty); } while (true ); do { wait(full); wait(mutex); signal(mutex); signal(empty); } while (true );
读者-写者问题
读者优先,如果当前获得数据库权限的是读者进程,则其他读者进程无需等待,读者进程只有在当前操作数据库的进程是写者的情况下才需要阻塞
写者有限,任何在等待获取数据库权限的写者进程都将比其他正在等待的读者进程先获得权限
前两种策略回到这写者或者读者饿死的情况,第三种策略保证没有任何进程会被无限阻塞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 semaphore mutex, wrt; int readcount;do { wait(mutex); readcount++; if (readcount == 1 ) { wait(wrt); } signal(mutex); wait(mutex); readcount--; if (readcount == 0 ) { signal(wrt); } signal(mutex); } while (true ); do { wait(wrt); signal(wrt); } while (true );
读写公平
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 int count = 0 ; semaphore mutex = 1 ; semaphore rw = 1 ; semaphore w = 1 ; wait(w) wait(mutex); count++; if (count == 0 ) { wait(rw); } signal(mutex); signal(w); reading; wait(mutex); count--; if (count == 0 ) { signal(rw); } signal(mutex); wait(w); wait(rw); writing; signal(rw); signal(w);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 int readcount = 0 , writecount = 0 ; semaphore rmutex = 1 , wmutex = 1 ; semaphore readTry; remaphore resource; do { wait(readTry); wait(rmutex); readcount++; if (readcount == 1 ) { wait(resource); } signal(rmutex); signal(readTry); wait(rmutex); readcount--; if (readcount == 0 ) { signal(resource); } signal(rmutex); } while (true ); do { wait(wmutex); writecount++; if (writecount == 1 ) { wait(readTry); } signal(wmutex); wait(resource); signal(resource); wait(wmutex); writecount--; if (writecount == 0 ) { signal(readTry); } signal(wmutex); } while (true );
哲学家就餐问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 enum {thinking, hungry, eating} state[5 ]; semaphore mutex = 1 ; semaphore self[5 ] = {0 }; void philosophere (int i) { while (true ) { thinking(); pickup(i); eating(); putdown(i); } } void pickup (int i) { wait(mutex); state[i] = hungry; test[i]; signal(mutex); wait(self[i]); } void test (int i) { if ((state[(i + 4 ) % 5 ] != eating) && (state[i] == hungry) && (state[(i + 1 ) % 5 ] != eating)) { state[i] = eating; signal(self[i]); } } void putdown (int i) { wait(mutex); state[i] = thinking; test[(i + 1 ) % 5 ]; test[(i + 4 ) % 5 ]; signal(mutex); }
另一种解法:
1 2 3 4 5 6 7 8 9 10 11 semaphore chopisticks[5 ] = {1 , 1 , 1 , 1 , 1 }; semaphore mutex = 1 ; P(int i) { wait(mutex); wait(chopisticks[i]); wait(chopisticks[(i + 1 ) % 5 ]); signal(mutex); eat; signal(chopisticks[i]); signal(chopisticks[(i + 1 ) % 5 ]); }
睡眠理发师问题
理发店有一位理发师,一把理发椅和n把供等待理发的顾客坐的椅子。如果没有顾客,理发师便在理发椅上睡觉,一个顾客到来时,顾客必须叫醒理发师,如果理发师正在理发时又有顾客到来,则如果有空椅子可坐,就坐下来等待,否则就离开
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int chairs = N;int waitings = 0 ;semaphore mutex; semaphore customer; semaphore barber; wait(mutex); if (waiting < chairs) { waitings++; signal(customer); signal(mutex); wait(barber); 理发; } else { signal(mutex); } wait(customer); wait(mutex); waitings--; signal(mutex); signal(barber); 理发;
考研题详解
1. 单向行驶问题
有桥如图所示,车辆方向如箭头所示,回答如下问题
(1) 假设该桥上每次只能有一辆车行驶,试用信号灯的wait(), signal()操作实现交通管理
(2) 假设该桥上不允许辆车交会,但允许同方向多个车一次通过(即桥上可由多个同方向行驶的车)。试用信号灯的wait(), signal()操作实现交通管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 semaphore bridge = 1 ; semaphore north_mutex = 1 ; semaphore south_mutex = 1 ; int count1 = 0 ; int count2 = 0 ; void car_from_north () { wait(north_mutex); count1++; if (count1 == 1 ) { wait(bridge); } signal(north_mutex); wait(north_mutex); count1--; if (count1 == 0 ) { signal(bridge); } signal(north_mutex); }
2.士兵过桥问题
独木桥的左右两端各停留一队士兵,左侧有 m 个,右侧有 n 个。两侧士兵均可上桥,但一旦有一侧士兵上桥,另一侧士兵必须等待已上桥一侧的士兵全部通过后才可上桥。试使用信号量描述此过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int left = 0 , right = 0 ; semaphore left_mutex = right_mutex = 1 ; semophore bridge = 1 ; do { wait(left_mutex); left++; if (left == 1 ) { wait(bridge); } signal(left_mutex); if (left == m) { signal(bridge); } } while (true )
3. 双向有限行驶问题
在南开大学和天津大学之间有一条小路 S -> T,小路中间有一个安全岛 M,安全岛能够同时容纳两辆自行车,可供两个已经从两端进入小路的自行车错车用。整个地图如下图,S 到 K 段的小路和 T 到 L 段的小路同时都只能允许一辆自行车通过。试设计一个算法,使来往的自行车都能顺利通过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 semaphore S = T = 1 ; semaphore SK = LT = 1 ; do { wait(S); wait(Sk); signal(SK); wait(LT); signal(LT); signal(S); } while (true );
4. 理发店问题
一个理发店配有一个有 10 个椅子的休息室和一个有理发椅的理发室。如果没有顾客则理发师睡觉;如果顾客来了而休息室、理发椅都没有空则离开;如果理发师在忙而有空的椅子,则顾客选择一个坐下等待;如果理发师在睡觉则顾客摇醒他。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 int count = 11 ; semaphore mutex = 1 ; semaphore barber_chair = 1 ; semaphore customers = 0 ; do { wait(mutex); if (count == 0 ) { signal(mutex); return ; } if (count == 11 ) { signal(customer); } } while (true )
5. 上机实习问题
某高校计算机系安排学生上机实习,机房共 30 台机器,有超过 60 名学生选课。规定每两个学生一组,一组占一台机器,协同完成实习。只有凑够两个学生且机房仍有空闲机器的情况下,门卫才允许该组学生进入机房。每组上机实习结束时需要由一名固定的老师检查完毕后,该组学生才可离开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 int count = 0 ; semaphore mutex = 1 ; semaphore teacher = 1 ; semaphore machine = 30 ; do { wait(mutex); count++; int id = count; if (count % 2 == 0 ) { wait(machine); } signal(mutex); wait(teacher); if (temp % 2 == 0 ) { signal(machine); wait(mutex); count -= 2 ; signal(mutex); } } while (true )
6. 吸烟者问题
假设一个系统有 3 个吸烟者进程和一个供应商进程,制造一根香烟需要三种材料各一份。三个吸烟者分别无限量的拥有三种材料中的一种。供应商进程可以无限量的供应这三种材料,一旦一个吸烟者想吸烟,则他向供应商发出请求,供应商会为这个吸烟者提供另外两种材料。供货商同时只能为一个吸烟者提供服务,多个吸烟者同时发出请求时按固定顺序服务。如此循环往复,请用信号量编写程序控制四个进程同步执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 bool smoker1, smoker2, smoker3; semaphore a = b = c = 0 ; semaphore smoker_request = 1 ; do { if (smoker1 == true ) { signal(b); signal(c); } if (smoker2 == true ) { signal(a); signal(c); } if (smoker3 == true ) { signal(b); signal(c); } } while (true ); do { wait(smoker_request); smoker1 = true ; wait(b); wait(c); signal(smoker_request); } while (true );
7. 苹果-句子或老虎与猪
有一个笼子可以容纳一只老虎或者两只猪,如果笼子中已经有猪,则老虎不能被放入。猎人 A 每次向笼子中放入一只老虎,猎人 B 每次向笼子中放入一只猪。饲养员每次会从笼子中取出一只老虎,厨师每次会从笼子中取出一只猪。对笼子的操作是互斥的。试用信号量描述此过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 semaphore pig = 0 , tiger = 0 ; semaphore coop = 1 ; semaphore pig_space = 2 ; semaphore pig_count_mutex = 1 ; int pig_count = 0 ; do { wait(coop); signal(tiger); } while (true ); do { wait(tiger); signal(coop); } while (true ); do { wait(pig_space); wait(pig_count_mutex); pig_count++; if (pig_count == 1 ) { wait(coop); } signal(pig); signal(pig_count_mutex); } while (true ); do { wait(pig); wait(pig_count_mutex); pig_count--; if (pig_count == 0 ) { signal(coop); } signal(pig_count_mutex); signal(pig_space); } while (true );
8.
三个进程P1、P2、P3互斥使用一个包含N(N>0)个单元的缓冲区。P1每次用produce()生成一个正整数并用put()送入缓冲区某一空单元。P2每次用getodd()从该缓冲区中取出一个奇数并用countodd()统计奇数个数。P3每次用geteven()从该缓冲区中取出一个偶数并用counteven()统计偶数个数。请用信号量机制实现这三个进程的同步与互斥活动,并说明定义的信号量的含义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 semaphore mutex; semaphore odd, even; semaphore empty = N; wait(empty); x = produce(); wait(mutex); put(); signal(mutex); if (x % 2 == 0 ) { signal(odd); } else { signal(even); } wait(odd); wait(mutex); getodd(); signal(mutex); signal(empty); countodd();
9.
在一个仓库可以存放A和B两种产品,要求:
每次只能存入一种产品
A产品数量 - B产品数量 < M
B产品数量 - A产品数量 < N
描述产品A与产品B的入库过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 semaphore mutex; semaphore Sa = M - 1 , Sb = N - 1 ; int countA = 0 , countB = 0 ;wait(Sa); wait(mutex); A产品入库; signal(mutex); signal(Sb); wait(Sb); wait(mutex); B产品入库; signal(mutex); signal(Sa);
10.
面包师有很多面包,由n个销售人员推销,每个顾客进店后取一个号,并且等待叫号,当一个销售人员空闲下来时,就叫下一个号,试设计一个使销售人员和顾客同步的算法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int i = 0 , j = 0 ; semaphore mutex_i, mutex_j; wait(mutex_i); 取号; i++; signal(mutex_i); 等待叫号i并购买面包; wait(mutex_j); if (j < i) { 叫号; j++; signal(mutex_j); 销售面包; } else { signal(mutex_j); 休息片刻; }
11.
设自行车生产线上有一只箱子,其中有N个位置(N>=3),每个位置可存放一个车架或一个车轮;又设有3个工人,其活动分别为:
工人1:加工一个车架,车架放入箱中
工人2:加工一个车轮,车轮放入箱中
工人3:箱中取一个车架,取一个车轮,组装为一台车
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 semaphore empty = N; semaphore wheel = 0 ; semaphore frame = 0 ; semaphore s1 = N - 1 ; semaphore s2 = N - 2 ; 加工一个车架; wait(s1); wait(empty); 车架放入箱中; signal(frame); 加工一个车轮; wait(s2); wait(empty); 车轮放入箱中; signal(wheel); wait(frame); 箱中取一个车轮; signal(empty); signal(s1); wait(wheel); wait(wheel); 箱中取两个车轮; signal(empty); signal(empty); signal(s2); signal(s2); 组装为一台车;
12.
系统中有多个生产者进程和多个消费者进程,共享一个能存放1000件产品的环形缓冲区(初始为空),当缓冲区未满时,生产者进程可以放入其生产的一个产品,否则等待;当缓冲区未空时,消费者进程可以从缓冲区取走一件产品,否则等待。要求一个消费者进程从缓冲区连续取出10间产品后,其他消费者才可以取产品。
这道题的解答感觉有问题,当产品的剩余数量不足10个的时候,消费者还控制着mutex1,但是有没有产品,生产者因为得不到mutex1,也不能生产,因此会造成死锁的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 semophere mutex1 = 1 , mutex2 = 1 ; semophere empty = n, full = 0 ; int count = 0 ;wait(empty); wait(mutex1); 放入一件产品; signal(mutex1); signal(full); wait(mutex1); for (int i = 0 ;i < 10 ;i++) { wait(full); wait(mutex2); 把产品放入缓冲区; signal(mutex2); signal(empty); 消费这件产品; } signal(mutex1);
13. 生产者-消费者问题扩展
桌子上有一只盘子,每次只能向其中放入一个水果,爸爸专向盘子中放苹果,妈妈专向盘子中放橘子, 儿子专吃盘子中的橘子,女儿专吃盘子中的苹果,只有盘子为空时,爸爸或妈妈就可以向盘子中放一个水果,仅当盘子中有自己需要的水果时,儿子或女儿可以从盘子中取出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 semaphore plate = 1 ; semaphore apple = 0 , orange = 0 ; wait(plate); put the apple; signal(apple); wait(plate); put the orange; signal(orange); wait(apple); take an apple from the plate; signal(plate); wait(orange); take an orange from the plate; signal(plate);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 semaphore emptyA = 10 , fullA = 0 ; semaphore emptyB = 10 , fullB = 0 ; semaphore mutexA, mutexB; wait(emptyA); wait(mutexA); 把A放入生产车间; signal(mutexA); signal(fullA); wait(emptyB); wait(mutexB); 把B放入生产车间; signal(mutexB); signal(fullB); wait(fullA); wait(mutexA); 从车间取一个A; signal(mutexA); signal(emptyA); wait(fullB); wait(mutexB); 从车间取一个B; signal(mutexB); signal(emptyB);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 semaphore mutex1, mutex2; semaphore count = 3 ; semaphore empty = 10 , full = 0 ; wait(empty); wait(count); wait(mutex1); 取水; signal(mutex1); wait(mutex2); 往水井倒水; signal(mutex2); signal(count); signal(full); wait(full); wait(count); wait(mutex2); 取水; signal(mutex2); signal(empty); signal(count);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 semaphore mutex; semaphore empty = 10 , full = 0 ; semaphore keeper = 1 ; wait(empty); wait(mutex); 取号; signal(mutex); signal(full); 等待叫号; wait(keeper); 获取服务; wait(full); 叫号; signal(empty); 为客户服务; signal(keeper);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 semaphore bridge; semaphore mutexN, mutexS; int northcount = 0 , southcount = 0 ;wait(mutexN); northcount++; if (northcount == 1 ) { wait(bridge); } signal(mutexN); 过桥; wait(mutexN); northcount--; if (northcount == 0 ) { signal(bridge); } signal(mutexN); = 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 semaphore movie1 = 0 , movie2 = 0 , movie3 = 0 ; semaphore mutex1, mutex2, mutex3; int count1 = 0 , count2 = 0 , count3 = 0 ;wait(movie1); wait(mutex1); count1++; signal(mutex1); 观看电影; wait(mutex1); count1--; if (count1 == 0 ) { signal(movie1); } signal(mutex1); wait(movie2); ... 同理; 最后signal(movie3);
1 2 3 4 5 6 7 8 9 10 11 12 wait(mutex1); ... signal(mutex2); wait(mutex2); 开车门; ... 关车门; signal(mutex1); ...
1 2 3 4 5 6 7 8 9 10 11 12 13 semophere emptyA, fullA, emptyB, fullB; semophere mutexA, mutexB; wait(fullA); wait(mutexA); 取邮件; signal(mutexA); signla(emptyA); 回答&提出问题; wait(emptyB); wait(mutexB); 放入B的邮箱中; signal(mutexB); signal(fullB);