【操作系统】第三章进程同步与进程通信

1. 为什么在操作系统中引入进程同步机制?

进程并发执行时,可能因共享资源 / 协作执行 出现 "竞态条件"(结果依赖执行顺序),或因协作逻辑需要协调执行步骤。引入同步机制是为了保证进程执行的正确性、共享资源的有序访问,避免数据不一致或逻辑错误

2. 有哪些方法可以实现进程的互斥与同步?

信号量机制(记录型、整型)

管程机制

互斥锁

条件变量

消息传递机制

3. 比较各种进程同步方法的优缺点?

方法 优点 缺点
信号量 灵活,支持复杂同步逻辑 易出错(如 PV 操作顺序、死锁)
管程 封装性好,更安全 实现较复杂,灵活性略低
互斥锁 实现简单,效率高 仅支持互斥,不支持复杂同步
消息传递 天然支持进程间通信 同步逻辑需依赖消息交互,开销略高

4. 实现进程互斥的基本原理是什么?

核心是保证 "临界资源" 在同一时刻仅被一个进程访问。通过同步机制(如信号量、锁)让进程进入 "临界区" 前先申请权限,访问完释放权限,从而避免并发冲突。

5. 说明记录型信号量的物理意义?

记录型信号量包含两个成员:

  • value:表示可用资源的数量(>0:可用资源数;=0:无可用资源;<0:等待队列中进程数的绝对值);
  • queue:存储因该资源阻塞的进程队列

物理意义是:通过 value 管理资源,通过队列管理等待进程,实现资源的有序分配与进程同步。

6. 为什么在生产者 - 消费者问题中 wait () 操作的顺序不能颠倒?

以 "生产者" 为例,若先执行 wait(empty)(申请空缓冲区)、再执行 wait(mutex)(申请互斥锁)的顺序颠倒:若先 wait(mutex) 获得锁,再 wait(empty) 但空缓冲区不足时,进程会阻塞,且持有互斥锁不释放 ,导致其他进程(生产者 / 消费者)无法访问临界资源,引发死锁

7. wait () 和 signal () 操作都必须是原子操作的确切含义是什么?为什么必须是原子操作?

原子操作的含义wait()/signal() 的执行过程不会被其他进程 / 线程打断,要么完整执行,要么不执行。

原因 :若操作非原子(如 wait() 中修改 value 的过程被打断),会导致信号量状态不一致,进而引发资源竞争、数据错误或死锁(比如多个进程同时 "误以为" 获得了资源)。

8. 信号量机制 wait () 和 signal () 的实现过程 + 经典同步问题的同步算法

wait (S) 实现

将信号量 S.value 减 1;

S.value < 0,则将当前进程加入 S.queue,并阻塞该进程。

signal (S) 实现

将信号量 S.value 加 1;

S.value ≤ 0,则从 S.queue 唤醒一个进程,将其插入就绪队列。

经典同步问题(如生产者 - 消费者) :设信号量 mutex=1(互斥访问缓冲区)、empty=N(空缓冲区数)、full=0(满缓冲区数)。

生产者:

复制代码
wait(empty);
wait(mutex);
// 向缓冲区放数据
signal(mutex);
signal(full);

消费者:

复制代码
wait(full);
wait(mutex);
// 从缓冲区取数据
signal(mutex);
signal(empty);

9. 什么是管程?举例说明引入管程有什么好处?

管程 :是一种封装了共享资源和同步操作的机制,进程通过调用管程的过程(函数)来访问资源,管程内部保证同一时刻仅一个进程执行其过程(自动实现互斥)。

好处 :例如 "生产者 - 消费者" 用管程实现时,无需手动管理 mutex 信号量,管程自动保证互斥;同时通过条件变量实现同步,代码更简洁、安全(避免 PV 操作顺序错误)。

10. 利用管程解决哲学家进餐问题的管程及哲学家进程

管程 DiningPhilosopher :包含条件变量 forks[5](表示叉子是否可用)、过程 pickup(i)(拿第 i 个哲学家的叉子)、putdown(i)(放叉子)。

复制代码
monitor DiningPhilosopher {
    condition forks[5];
    // 拿叉子:需同时拿到左右叉
    procedure pickup(int i) {
        if (叉子i或i+1被占用)
            wait(forks[i]);
        // 标记叉子为占用
    }
    // 放叉子:释放左右叉并唤醒等待的哲学家
    procedure putdown(int i) {
        // 标记叉子为可用
        signal(forks[(i+1)%5]);
        signal(forks[i]);
    }
}

哲学家进程

复制代码
while (true) {
    思考;
    DiningPhilosopher.pickup(i);
    进餐;
    DiningPhilosopher.putdown(i);
}

11. 三个进程 PA、PB、PC 的文件打印同步(记录型信号量)

设信号量:

s1=1(缓冲区 1 的互斥 / 初始可用)、s2=0(缓冲区 2 初始无数据)、s3=0(缓冲区 2 数据已处理 / 初始无数据)。

PA 进程

复制代码
while (true) {
    从磁盘读记录到缓冲区1;
    signal(s2); // 通知PB缓冲区1有数据
    wait(s1);   // 等待PB取走数据(缓冲区1可用)
}

PB 进程

复制代码
while (true) {
    wait(s2);   // 等待PA写入缓冲区1
    复制缓冲区1到缓冲区2;
    signal(s1); // 通知PA缓冲区1可用
    signal(s3); // 通知PC缓冲区2有数据
}

PC 进程

复制代码
while (true) {
    wait(s3);   // 等待PB写入缓冲区2
    打印缓冲区2内容;
    // 无需signal,因为缓冲区2仅PC使用(或按需加信号量)
}

12. 线程 P(写温度)和 Q(读温度)的同步问题

(1) 数据区 B 的结构 :采用队列(如先进先出队列),因为 Q 需要 "最新的检测数据",队列可按顺序存储数据,Q 取队尾(最新)数据。

(2) 同步关系

  • P 和 Q互斥访问 B 区(避免读写冲突);
  • Q 需等待 P 写入数据(B 区为空时 Q 阻塞)。

(3) 记录型信号量实现 :设信号量 mutex=1(互斥访问 B 区)、has_data=0(B 区是否有数据)。

线程 P:

复制代码
while (true) {
    检测温度;
    wait(mutex);
    将温度写入B区;
    signal(mutex);
    signal(has_data); // 通知Q有新数据
}

线程 Q:

复制代码
while (true) {
    wait(has_data); // 无数据则阻塞
    wait(mutex);
    从B区取出最新温度;
    signal(mutex);
    处理温度数据;
}

13. 进程通信方式 + 管道的定义与特点

进程通信方式:包括管道、消息队列、共享内存、信号量、套接字等。

管道 :是一种基于文件的半双工通信机制,用于父子 / 亲缘进程间通信,数据以字节流形式传输。

  1. 匿名管道:特点:仅用于亲缘进程;无文件名,通过文件描述符访问;随进程退出而销毁。
  2. 命名管道:特点:可用于任意进程;有文件名(存在于文件系统);独立于进程生命周期(需手动删除)。

14. 消息缓冲队列机制的实现原理

消息缓冲队列是基于消息的通信机制,原理:

  1. 发送进程将消息封装为消息缓冲区(含目标进程 ID、消息长度、内容等);
  2. 通过 send() 原语,将消息缓冲区插入目标进程的消息队列(需互斥访问队列,用信号量实现);
  3. 接收进程通过 receive() 原语,从自己的消息队列中取出消息缓冲区,读取内容;
  4. 若消息队列为空,接收进程会阻塞,直到有消息到来。
相关推荐
有泽改之_2 小时前
摄影后期如何将图片变得通透与darktable操作
笔记
凸凹恼2 小时前
【每天一个小笔记】01 Docker 部署项目
笔记·docker
Dream Algorithm3 小时前
订单簿买卖
笔记·金融
代码游侠3 小时前
学习笔记——TCP 传输控制协议
linux·网络·笔记·网络协议·学习·tcp/ip
深蓝海拓3 小时前
PySide6从0开始学习的笔记(十二) QProgressBar(进度条)
笔记·python·qt·学习·pyqt
悟凡爱学习3 小时前
zigbee学习笔记 --认识什么是zigbee
笔记·学习
fanged3 小时前
Pico裸机2(汇编基础)(TODO)
笔记
老王熬夜敲代码3 小时前
C++的decltype
开发语言·c++·笔记
沐风听雨_A3 小时前
海康IP摄像头激活与配置笔记
笔记·嵌入式硬件