1.本文内容总结自 B站 《操作系统-哈工大李治军老师》,内容非常棒,墙裂推荐;
2.进程同步: 让进程间的合作变得合理有序;
3.通过 信号量 来实现进程同步 ;
4.操作系统借助信号量实现进程合作,进程走走停停;(进程什么时候停,在哪个地方停特别重要)

【例1】司机与售票员例子
| 司机 | 售票员 |
| While(true) { 启动车辆;// 等待信号1 正常运行; 到站停车;// 发送信号2 } | While(true) { 关门;// 发送信号1 售票; 开门; // 等待信号2 } |
【例2】生产者消费者

| 生产者 | 消费者 |
| 阻塞直到 counter 不等于 BUFFER_SIZE; 生产数据后,counter加1,类似向消费者发送信号; | 阻塞直到counter不等于0; 消费数据后,counter减1,类似向生产者发送信号; |
进程同步定义: 需要让进程走走停停,保证多进程合作的合理有序;

1)只发信号还不能解决全部问题;

2)问题描述:
出现的问题:
3)信号量
信号量不仅需要记录睡眠和唤醒,还需要记录当前阻塞的生产者个数等其他信息;

4)信号量开始工作
| 步骤 | 生产者与消费者执行详情 | 信号量 sem值 |
| 1 | 缓冲区满,生产者P1执行, P1睡眠,信号量减1;则信号量为-1;(信号量-1表示1个生产者睡眠) | -1 |
| 2 | 生产者P2执行, P2睡眠,信号量减1;则信号量为-2(表示2个生产者睡眠) | -2 |
| 3 | 消费者执行1次循环, wakeup唤醒P1后,信号量加1得到-1;(表示1个生产者睡眠) | -1 |
| 4 | 消费者再执行1次循环, wakeup唤醒P2,信号量加1得到0;(没有生产者睡眠) | 0 |
| 5 | 消费者在执行一次循环;信号量加1;(表示有1个可用缓冲空间) | 1 |
| 6 | 生产者P3执行,信号量减1; | 0 |
信号量sem值含义:
【小结】

5)基于信号量的进程合作
多个进程合作完成一件事,多个进程在执行过程中,执行的推进顺序要合理有序;
具体地,在执行一定程度后,进程根据信号量判断是否停下来等待;
1)信号量定义:一种特殊整型变量,量用来记录,信号用来判断是否睡眠sleep和唤醒wakeup;
2)信号量代码
- // 信号量代码
- struct semaphore()
- {
- // 记录资源个数
- int value ;
- // 进程阻塞队列(记录在该信号量上等待的进程)
- PCB *queue;
- }
-
- // 生产者:消费资源(这里消费资源指的是生产者消费一个空闲缓冲区,或一个数组项)
- P (semaphore s)
- {
- s.value--; // 消费资源
- if (s.value < 0) {
- sleep(s.queue); // 当前生产者进程睡眠
- }
- }
-
- // 消费者:产生资源 (这里产生资源指的是消费者释放一个空闲缓存区,或一个数组项)
- V (semaphore s)
- {
- s.value++; // 释放资源
- if (s.value <=0 ) {
- wakeup(s.queue); // 消费者唤醒睡眠的生产者进程
- }
- }

【补充】 荷兰语中

1)信号量解决生产者消费者问题的源代码
- // 1 用文件定义共享缓冲区
- int fd = open("buffer.txt");
- write(fd, 0, sizeof(in)); // 写入数据到in位置
- read(fd, 0, sizeof(out)); // 从out位置读取数据
-
- // 2 信号量的定义和初始化
- semaphore full = 0; // 表示缓冲区中已生产的数据(内容)个数,或已用缓冲区个数;
- semaphore empty = BUFFER_SIZE; // 表示空闲缓冲区个数
- semaphore mutex = 1; // 互斥信号量,同时只能有1个进程进去;
-
- // 3 生产者
- Producer(item) {
- P(empty); // 生产者先测试empty信号量是否为0(为0表示没有空闲缓冲区)
- P(mutex);
- // 读取in,把item写入到in的位置上 (生产操作)
- V(mutex);
- V(full); // 增加数据(内容)个数
- }
-
- // 4 消费者
- Consumer() {
- P(full); // 消费者先测试缓冲区是否存在内容,则没有则阻塞
- P(mutex); // 判断是否可以访问文件,mutex是互斥信号量,同时只有1个进程可以访问文件(mutex减1, 获取mutex信号量或锁)
- // 读取out,从文件中的out位置读出到item,打印item (消费操作)
- V(mutex); // mutex加1,释放mutex 信号量
- V(empty);// 消费者在消费完后,增加空闲缓冲区个数
- }