进程同步(1)之PV操作/信号量/互斥量
OS中,信号量表示资源实体数,早期信号量只是一个Int,单纯从一个int的确可以表示出资源数,但是当有多个进程抢占CPU时,下一次的抢占将会造成进程队列的混乱.例如:ABCD 4个进程, A先抢到了CPU,在下一次进行CPU抢占时,将会导致BCD的次序是不可预知的.所以引进了一个信号量的数据结构semaphore.
PV
PV操作是由荷兰人Dijkstra提出的(荷兰语中,P:Proberen是检测的意思,V:Verhogen是增量的意思).PV操作可以解决并发进程间CPU的竞争,又能解决并发进程的协作关系.PV操作是遵循的公平策略是FCFS.
注意:PV操作是一段原语操作.学过数据库,我们都知道原语是指一段代码,要么全做,要么不做,这段代码未完成是不可中断的.
看以下一段代码
1 typedef struct semaphore{ 2 3 int value; //信号量值 4 5 struct pcb *list;//信号量队列指针 6 7 }; 8 9 //进行P测试(无资源则挂起) 10 11 void P(semaphore &s){ 12 13 s.value--; 14 15 if(s.value<0){//判断是否还有资源,没有资源则休眠,有资源则通过P测试 16 17 W.(s.list);//进程休眠操作wait. 18 19 } 20 21 } 22 23 //进行V操作(队列有休眠进程则唤醒唤醒) 24 25 void V(semaphore &s){ 26 27 s.value++; 28 29 if(s.value<=0){//判断是否有进程在等待,有的话则唤醒进程 30 31 R(s.list);// 释放进程 release. 32 33 } 34 35 }
这段就是PV操作的核心代码.
P操作中,如果没有资源则会阻塞自己(调用P操作的进程),并将自己放入等待调度的队列.
V操作中,如果有被阻塞的队列则唤醒进程.
Note:
value初始值为资源数.
value等于0, 资源刚好用完,
value大于0, 还有资源.
value小于0, 绝对值等于挂起队列中的进程数.
互斥量
互斥量从字面很容易理解,就是解决进程间的互斥关系.
一般互斥量用在并发进程进入临界区前的测试.(临界区:并发进程中与共享变量有关的代码段)
实现代码如下:
1 semaphore mutex; 2 3 mutex = 1; 4 5 void M(){ 6 7 P(mutex); 8 9 {临界区} 10 11 V(mutex); 12 13 }
Note:
mutex取值为1/0,mutex等于1时表示临界区可用.mutex等于0表示临界区不可用.mutex也可以对共享资源加锁.
概念总结:
1)同步:信号量初始化S0=n,S1=0,两个并发进程需要两个信号量,后做的进程初始化为0,另一个进程初始化值为资源数.当引入更多并发进程时,每增加一个进程则相应增加一个信号量.
2)互斥:信号量有且只有一个,初始值为1.