信号量与PV操作
问题的提出
- TS或swap指令管理临界区,采用忙式轮询,效率低
- 关开中断管理临界区,不便交给用户程序使用
信号量的构思
一种可动态定义的软件资源:信号量
-
核心数据结构:等待进程队列
-
信号量声明:资源报到,建立队列
-
申请资源的原语:若申请不得,调用进程入队等待
-
归还资源的原语:若队列中有等待进程,需释放
-
信号量撤销:资源注销,撤销队列
记录型信号量的定义
记录型信号量:一种带数值的软资源
PV操作解决进程互斥问题框架
semaphore s;
s = 1;
cobegin
process Pi {
···
P(s);
临界区;
V(s);
···
}
coend;
例:PV操作解决机票问题
int A[m];
semaphore s;
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; // 无条件跳转至Li标记处
}
coend;
int A[m];
semaphore s[m];
for(int j = 0; j < m; j++){
s[j] = 1;
}
cobegin
Process Pi {
int Xi;
Li:按旅客订票要求找到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 Li; // 无条件跳转至Li标记处
}
coend;
PV操作解决进程同步问题
进程同步:并发进程为完成共同任务基于某个条件来协调执行先后关系而产生的写作制约关系(一个进程的执行等待来自于其他进程的消息)
解决的基本思路
- 定义一个信号量:其数值代表可用消息数
- 等待消息进程:执行P,无消息则等待
- 发出消息进程:执行V,有进程等待则释放
例:1生产者1消费者1缓冲区问题
- 生产者和消费者共享缓冲区
- 缓冲区有空位时,生产者可放入产品,否则等待
- 缓冲区有产品时,消费者可取出产品,否则等待
程序框架
解决思路
同步关系1:消费者一开始在等待产品到来,考虑设置一个信号量(等待产品);一开始无产品,初值为0
同步关系2:生产者则在等待缓冲区中有空位,也可设置一个信号量(等待缓冲区);一开始缓冲区有空位,初值为1
例:1生产者1消费者N缓冲区问题
例:N生产者N消费者N缓冲区问题
苹果橘子问题
A、B分别产生苹果、橘子,C、D分别消费苹果、橘子,共享同一缓冲区
同步关系1:有苹果
同步关系2:有橘子
同步关系3:有空位
int plate;;
semaphore sp; // 盘子里可以有几个水果
semaphore sg1; // 盘子里有橘子
semaphore sg2; // 盘子里有苹果
sp = 1; // 盘子里只能放一个水果
sg1 = 0; // 盘子里没有橘子
sg2 = 0; // 盘子里没有苹果
/* --------------------------------------------- */
process A {
L1: 削一个苹果;
P(sp);
把苹果放入plate;
v(sg2);
goto L1;
}
process B {
L2: 剥一个橘子;
P(sp);
把橘子放入plate;
v(sg1);
goto L2;
}
process C {
L3: P(sg2);
从盘子中取苹果;
V(sp);
吃苹果;
goto L3;
}
process D {
L4: P(sg1);
从盘子中取橘子;
V(sp);
吃橘子;
goto L4;
}