信号量是一种变量类型,用一个记录型数据结构表示,有两个分量:信号量的值和信号量队列指针
除了赋初值外,信号量仅能通过同步原语PV对其进行操作
s.value为正时,此值为封锁进程前对s信号量可施行的P操作数,即s代表实际可用的物理资源
s.value为负时,其绝对值为对信号量s实施P操作而被封锁并进入信号量s等待队列的进程数,即登记排列在s信号量队列之中等待的进程个数
s.value为0时,无资源且无进程等待
信号量按其取值可分为二值信号量和一般信号量(计数信号量),记录型信号量和PV操作定义为如下数据结构和不可中断过程:
typedef struct semaphore { int value; struct pcb *list; //信号量队列指针 } void P(semaphore s){ s.value--; if(s.value<0) sleep(s.list); //若信号量值小于0,执行P操作的进程调用sleep(s.list)阻塞自己,被置成等待信号量s状态并移入s信号量队列,转向进程调度程序 } void V(semaphore s){ s.value++; if(s.value<=0) wakeup(s.list); //若信号量小于等于0,则调用wakeup(s.list)从信号量s队列中释放一个等待信号量s的进程并转换成就绪态,进程则继续运行 }
二值信号量虽然仅能取值0、1,但它和其它记录型信号量有一样的表达能力
- 机票问题
注意:(1)P操作与V操作在执行路径上必须一一对应,有一个P操作就有一个V操作;(2)输出一张票的操作不应放在临界区内
int A[m]; Semaphore s = 1; cobegin process Pi { int Xi; Li:按旅客定票要求找到A[j]; P(s); Xi = A[j]; If (Xi>=1) { Xi=Xi-1; A[j]=Xi;V(s); 输出一张票;} else {V(s); 输出票已售完;} goto Li; } coend;
只有相同航班的票数才是相关的临界资源,所以用一个信号量s处理全部机票会影响进程并发度
可以让每一个航班都有自己的临界区,把信号量改为s[m]
int A[m]; Semaphore s[m]; //每一个航班都有自己的临界区 For (int j=0;j<m;i++) s[j] = 1; cobegin process Pi { int Xi; L1:按旅客定票要求找到A[j]; P(s[j]); Xi = A[j]; If (Xi>=1) { Xi=Xi-1; A[j]=Xi;V(s[j]); 输出一张票; } else {V(s[j]); 输出票已售完;} goto L1; } coend;
- 生产者消费者问题
(1)1生产者1消费者1缓冲区问题
int