标签:mutex cti 原理 描述 and reader 行操作 优先 位置
本人水平有限,若有错误,欢迎读者及时指出,万分感谢!
? P/V操作由P操作原语和V操作原语组成,其意义是在一个整型变量S上定义了两个操作,该操作变量被称之为信号量S,只能由P操作和V操作进行修改。S必须置一次且只能置一次初值,S >= 0表示当前可用的资源的数目,S = 1实现互斥(二元信号量mutex),S > 1实现同步(通用信号量)。多个进程要操作同一个临界资源就是互斥,多个进程要按一定的顺序执行就是同步。
? 进程A分别要执行a1和a2,进程B分别要执行b1和b2,两个进程在执行过程中一点汇合,直至两者都到后才能继续执行。a1永远在b2之前,b1永远在a2之前,a1和b1的次序不加限制。
? 定义两个信号量,aArrived
,bArrived
,并且初始化为0,表示a和b是否执行到汇合点。
Thread A:
a1
V(aArrived)
P(bArrived)
a2
Thread B:
b1
V(bArrived)
P(aArrived)
b2
? 实现mutex的泛化,使得n个进程能够同时运行在临界区。
? 设置信号量multiplex = n
。
P(multiplex)
critical section //临界区操作
V(multiplex)
? 对rendezvous进行泛化,使其能够用于多个进程,用于进程组的同步。
// n = the number of threads
count = 0 //到达汇合点的进程个数
semaphore mutex = 1 //保护count
semaphore queue = 0 //进程到达之前都是0,用于进程排队
P(mutex)
count = count + 1
V(mutex)
if count == n : V(queue) //第n个进程到来,唤醒一个进程,触发。
P(queue) //前n-1个进程在此排队
V(queue) //一旦进程被唤醒,有责任唤醒下一个进程
? AND型信号量集是指同时需要多个资源且每种占用一个资源时的信号量集操作,将进程需要的所有共享资源一次全部分配给它,待该进程使用完再一起释放。AND型信号量集P原语为SP,V原语为SV。
SP实现原理
SP(S1, S2, ... , Sn)
? if S1 >= 1 and ... and Sn >= 1 then
? for i := 1 to n do
? Si := Si - 1;
? endfor
? else
? wait in Si; //将进程调度到第一个小于1的信号量Si的等待队列
? endif
SV实现原理
SV(S1, S2, ... ,Sn)
? for i := 1 to n do
? Si := Si + 1;
? wake waited process on Si
? endfor
? 一般信号量集是指同时需要多种资源、每种占用的数目不同、且可分配的资源还存在一个临界值时的信号量处理。
? 在AND型信号量集的基础上进行补充:进程对信号量集Si的测试值为ti
(用于信号量的判断,即Si >= ti
,表示资源数量低于ti
时,不予分配),资源的申请量为di
(用于信号量的增减,即Si = Si - di
和Si = Si + di
)
SP(S1, t1, d1; ...; Sn, tn, dn)
SP(S1, t1, d1; ...; Sn, tn, dn)
? if S1 >= t1 and ... and Sn >= tn then
? for i := 1 to n do
? Si := Si - di;
? endfor
? else
? wait in Si;
? endif
SV(S1, d1; ...; Sn, dn)
SV(S1, d1; ...; Sn, dn)
? for i := 1 to n do
? Si := Si + di;
? wake waited process
? endfor
? 当事件发生时,生产者线程创建一个事件对象,放入事件缓冲区,消费者线程从缓冲区取出事件,进行响应处理。
typedef int semaphore;
semaphore mutex = 1; //用于实现临界区互斥
semaphore empty = N; //指示空缓冲块数目
semaphore odd = 0; //指示临界区奇数数目
semaphore even = 0; //指示临界区偶数数目
P1:
while (true) {
? num = produce();
? P(empty);
? P(mutex);
? put(num);
? V(mutex);
? if (num % 2 == 0) {
? V(even);
? } else {
? V(odd);
? }
}
P2:
while (true) {
? P(odd);
? P(mutex);
? getodd();
? countodd();
? V(mutex);
? V(empty);
}
P3:
while (true) {
? P(even);
? P(mutex);
? geteven();
? counteven();
? V(mutex);
? V(empty);
}
typedef int semaphore;
semaphore mutex = 1;
semaphore empty = M;
semaphore full = 0;
厨师:
void producer(void) {
? while (true) {
? SP(empty, M, M);
? P(mutex);
? putServingInPot();
? V(mutex);
? SV(full, M);
? }
}
野人:
void consumer(void) {
? while (true) {
? P(full);
? P(mutex);
? getServingFromPot();
? eat();
? V(mutex);
? V(empty);
? }
}
product buffer[1000];
semaphore empty = 1000; //指示空缓冲块数目
semaphore full = 0; //指示满缓冲块数目
semaphore mutex1 = 1; //用于实现临界区互斥和生产者之间的互斥
semaphore mutex2 = 1; //用于消费者之间的互斥
int i = 0;
int j = 0;
void producer(void) {
? produce newProduct;
? P(empty);
? P(mutex1);
? buffer[i] = newProduct;
? i = (i + 1) % 1000;
? V(mutex1);
? V(full);
}
void consumer(void) {
? P(mutex2);
? for (int t = 0; t < 10; t++) {
? P(full);
? P(mutex1);
? consume buffer[j];
? j = (j + 1) % 100;
? V(mutex1);
? V(empty);
? }
? V(mutex2);
}
int waiting_id = 0; //当前客户编号
semaphore waiting_mutex = 1; //对waiting_id互斥访问
int next_id = 0; //下一位要服务客户编号
semaphore next_mutex = 1; //对next_id互斥访问
Customer:
P(waiting_mutex);
waiting_id++;
V(waiting_mutex);
Server:
while (true) {
? P(next_mutex);
? P(waiting_id);
? if (next_id < waiting_id) {
? next_id++;
? }
? V(waiting_id);
? V(next_mutex);
? serve next_id;
}
-M≤A物品数量-B物品数量≤N,其中M和N为正整数
,试用信号量和PV操作描述A、B两种物品的入库过程。semaphore mutex = 1;
semaphore sa = N;
semaphore sb = M;
A:
while (true) {
? P(sa);
? P(mutex);
? A产品入库;
? V(mutex);
? V(sb);
}
B:
while (true) {
? P(sb);
? P(mutex);
? B产品入库;
? V(mutex);
? V(sa);
}
oxygen = 0; //氧原子的计数器
hydrogen = 0; //氢原子的计数器
semaphore mutex = 1; //保护计数器的mutex
Barrier barrier(3); //3表示需要调用3次wait后barrier才开放
//3个线程调用bond后的同步点,之后允许下一个线程继续
semaphore oxyQueue = 0; //氧气线程等待的信号量
semaphore hydroQueue = 0; //氢气线程等待的信号量
//用在信号量上睡眠来模拟队列
P(oxyQueue) //表示加入队列
V(oxyQueue) //表示离开队列
Oxygen:
P(mutex);
oxygen += 1;
if (hydrogen >= 2) {
? V(hydrogen);
? V(hydrogen);
? hydrogen -= 2;
? V(oxyQueue);
? oxygen -= 1;
} else {
? V(mutex);
}
P(oxyQueue);
bond();
barrier.wait()
V(mutex); //构建H2O成功,当三个线程离开barrier时候,最后那个线程拿着mutex,虽然我们不知道哪个线程拿着mutex,但我们一定要释放一次。
Hydrogen:
P(mutex);
hydrogen += 1;
if (hydrogen >= 2 && oxygen >= 1) {
? V(hydroQueue);
? V(hydroQueue);
? hydrogen -= 2;
? V(oxyQueue);
? oxygen -= 1;
} else {
? V(mutex);
}
P(hydroQueue);
bond();
barrier.wait();
? 对共享资源的读写操作,任一时刻“写者”最多只允许一个,而“读者”则允许多个,“读-写”互斥,“写-写”互斥,“读-读”允许。读者算法的模式:第一个读线程加锁,最后一个读线程解锁。
int readers = 0 //记录临界区内读者的数目
semaphore mutex = 1 //保护对readers的访问
semaphore roomEmpty = 1 //对屋子的互斥访问,初值为1表示一个空屋子
Writer
P(roomEmpty);
write; //critical region
V(roomEmpty);
Reader
P(mutex);
readers = readers + 1;
if (readers == 1) {
? P(roomEmpty);
}
V(mutex);
read; //critical region
P(mutex);
readers = readers - 1;
if (readers == 0) {
? V(roomEmpty);
}
V(mutex);
增加一个限制条件:同时读的“读者”最多Rn个,mx
表示“允许写”,初值为1,L
表示“允许读者数目”,初值为Rn。
Writer
SP(mx, 1, 1; L, Rn, 0);
write
SV(mx, 1);
Reader
SP(L, 1, 1; mx, 1, 0);
read
SV(L, 1);
? 用信号量queue
和两个连续P(queue)
和V(queue)
组成。当queue
值为0,闸机关闭,任何进程不能进入;当queue
值为1,多个进程可以轮流排队通过。
int readers = 0;
semaphore mutex = 1;
semaphore roomEmpty = 1;
semaphore turnstile = 1;
Writer
P(turnstile);
P(roomEmpty);
write; //critical region
V(turnstile);
V(roomEmpty);
Reader
P(turnstile);
V(turnstile);
P(mutex);
readers = readers + 1;
if (readers == 1) {
? P(roomEmpty);
}
V(mutex);
read; //critical region
P(mutex);
readers = readers - 1;
if (readers == 0) {
? V(roomEmpty);
}
V(mutex);
int readers, writers = 0;
semaphore mutexW = 1; //保护对writes的访问
semaphore mutexR = 1; //保护对readers的访问
semaphore wMutex = 1; //当有读者或写者进行操作时,阻止其他写者进行操作
semaphore rMutex = 1; //当有写者进行操作时,阻止其它读者进行操作
semaphore MUTEX = 1; //在写者优先算法中,这个信号量很重要,目的是在rMutex上不允许建设长队列,我们可以设想一种情况:如果没有该信号量,则当写进程访问时,所有的读进程都等待在rMutex的队列上;当写进程结束访问,开始处理第一个读进程(readers++),但此时有写进程也准备访问,根据写者优先的要求,应该先执行写进程,但此时写进程会等待在rMutex的队列上,与准备访问(还没处理)的读进程(可能有成百上千个)共同竞争读进程释放的rMutex,结果可想而知。所以只允许一个进程在rMutex上排队,其他进程在等待rMutex之前,在MUTEX上排队。
Writer:
P(mutexW);
writes = writers + 1;
if (writes == 1) {
? P(rMutex);
}
V(mutexW);
P(wMutex);
write; //critical region
V(wMutex);
P(mutexW);
writes = writes - 1;
if (writes == 0) {
? V(rMutex);
}
V(mutexW);
Reader:
P(MUTEX);
P(rMutex);
P(mutexR):
readers = readers + 1;
if (readers == 1) {
? P(wMutex);
}
V(mutexR):
V(rMutex);
V(MUTEX);
read; //critical region
P(mutexR);
readers = readers - 1;
if (readers == 0) {
? V(wMutex);
}
V(mutexR);
? 理发店有一位理发师、一把理发椅和n把供等候理发的乘客坐的椅子;如果没有顾客,理发师便在理发椅上睡觉,当一个顾客到来时,叫醒理发师;如果理发师正在理发时,又有顾客来到,则如果有空椅子可坐,就坐下来等待,否则就离开。
? 互斥访问资源:排队的顾客数(计数器waiting)
? 同步:顾客唤醒理发师、理发师唤醒下一位等待顾客
semaphore customers = 0; //等待理发的顾客
semaphore barbers = 0; //等待顾客的理发师
semaphore mutex = 1; //互斥访问waiting
int waiting = 0; //等待的顾客数(不包含正在理发的顾客)
int CHAIRS = 10;
Barber:
while (true) {
? P(customers);
? P(mutex);
? waiting = waiting - 1;
? V(mutex);
? V(barbers);
? cut hair();
}
Customer
P(mutex);
if (waiting < CHAIRS) {
? waiting = waiting + 1;
? V(mutex);
? V(customers);
? P(barbers);
? get haircut();
} else {
? V(mutex);
}
? 5个哲学家围绕一张圆桌而坐,桌子上放着5支筷子,每两个哲学家之间放一支;哲学家必须拿到左右两只筷子才能吃饭。假设哲学家用 i=0~4 编号,筷子也是,哲学家 i 必须拿到筷子 i 和筷子 i + 1 才能进食。
需要满足条件:
方案:
至多只允许四个哲学家同时(尝试)进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。
semaphore dinners = 4;
semaphore chopstick[] = {1, 1, 1, 1, 1};
Philosopher i :
while (true) {
? think();
? P(dinners);
? P(chopstick[(i + 1) % 5]);
? P(chopstick[i]);
? eat();
? V(chopstick[(i + 1) % 5]);
? V(chopstick[i]);
? V(dinners);
}
同时拿起两根筷子,否则不拿起。
semaphore chopstick[] = {1, 1, 1, 1, 1};
Philosopher i:
while (true) {
? think();
? SP(chopstick[(i + 1) % 5], chopstick[i]);
? eat();
? SV(chopstick[(i + 1) % 5], chopstick[i]);
}
对筷子进行编号,奇数号哲学家先拿左,再拿右;偶数号相反。
semaphore chopstick[] = {1, 1, 1, 1, 1};
Philosopher i:
while (true) {
? if (i % 2 == 0) {
? think();
? P(dinners);
? P(chopstick[(i + 1) % 5]);
? P(chopstick[i]);
? eat();
? V(chopstick[(i + 1) % 5]);
? V(chopstick[i]);
? V(dinners);
? } else {
? think();
? P(dinners);
? P(chopstick[i]);
? P(chopstick[(i + 1) % 5]);
? eat();
? V(chopstick[i]);
? V(chopstick[(i + 1) % 5]);
? V(dinners);
? }
}
int emptyChairs = n; //空闲的座位数
semaphore chair = n; //信号量,表示空闲的座位数
semaphore mutex = 1; //保护对emptyChairs的互斥访问
semaphore queue = 1; //对等待顾客的互斥访问,每次只处理一个等待顾客
P(queue);
P(mutex);
if (emptyChairs == 0) {
? V(mutex);
? SP(chair, 5, 1);
} else {
? V(mutex);
? SP(chair, 1, 1);
}
P(mutex);
emptyChairs--;
V(mutex);
V(queue);
eat;
P(mutex);
emptyChairs++;
V(mutex);
SV(chair, 1);
semaphore noSearch = 1; //表示临界区无搜索进程
semaphore noInsert = 1; //表示临界区无插入进程
semaphore iMutex = 1; //用于插入进程之间的互斥
int insertNum = 0; //表示插入进程的数目
semaphore mutexInsertNum = 1; //保护对insertNum的互斥访问
int searchNum = 0; //表示搜索进程的数目
semaphore mutexSearchNum = 1; //保护对searchNum的互斥访问
Delete:
P(noSearch);
P(noInsert);
delete();
V(noInsert);
V(noSearch);
Insert:
P(mutexInsertNum);
insertNum++;
if (insertNum == 1) {
? P(noInsert);
}
V(mutexInsertNum);
P(iMutex);
insert();
V(iMutex);
P(mutexInsertNum);
insertNum--;
if (insertNum == 0) {
? V(noInsert);
}
V(mutexInsertNum);
Search:
P(mutexSearchNum);
searchNum++;
if (searchNum == 1) {
? P(noSearch);
}
V(mutexSearchNum);
search();
P(mutexSearchNum);
searchNum--;
if (searchNum == 0) {
? V(noSearch);
}
V(mutexSearchNum);
以上部分内容引自课件,如有侵权,请及时联系我删除!
标签:mutex cti 原理 描述 and reader 行操作 优先 位置
原文地址:https://www.cnblogs.com/nickhan-cs/p/12778923.html