计算机操作系统(十六)进程同步

发布于:2025-06-24 ⋅ 阅读:(19) ⋅ 点赞:(0)


前言

  • 在上一篇博客中,我们系统剖析了 死锁底层原理与典型场景
  • 作为并发编程中另一核心议题,进程同步机制不仅是规避死锁风险的关键手段,更是保障多进程协同工作正确性的基础框架。
  • 本篇将从同步需求的本质出发,深入探讨进程 同步问题,信号到信号量,临界区,信号量的实现与使用

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的操作系统博客专栏
https://blog.csdn.net/2402_83322742/category_12916780.html?spm=1001.2014.3001.5482


一、进程同步问题

1.1 什么是进程?

进程就是计算机里正在运行的程序,比如你同时打开微信、浏览器、Word,每个都是一个进程。

1.2 为什么需要同步?

例子:银行账户取钱
假设你和朋友同时用手机给同一个账户转账100元,理想情况账户应该增加200元,但如果没有"排队"机制,可能出现:

  1. 你先读取账户余额1000元,朋友同时也读取1000元
  2. 你转账后余额变为1100元,朋友转账后也写回1100元
  3. 最终账户只增加了100元,钱"消失"了!

这就是进程同步问题:多个进程访问共享资源时,结果可能出错,必须让它们"有序"操作。

二、从信号到信号量

2.1 什么是信号?

信号是操作系统给进程的"通知",比如按Ctrl+C就是给进程发一个"终止信号"

  • 但信号只能发通知,无法解决复杂的排队问题(比如控制多少人能同时访问资源)。

2.2 信号量的诞生

信号量就像"钥匙管理员",它做两件事:

  • 记录当前可用资源的数量(比如有3把钥匙)
  • 控制进程能否获取资源(拿到钥匙才能进门)

例子:图书馆自习室
自习室有10个座位(资源数量),信号量就像登记本,记录当前空座位数。想进自习室的人先看登记本:

  • 有空位:拿走一个座位(登记本减1),进去学习
  • 没空位:在门口等待,直到有人离开(登记本加1时被通知)

三、临界区:不能多人同时进的"小房间"

3.1 什么是临界区?

临界区是一段代码,这段代码访问共享资源(比如变量、文件)时,必须独占访问。就像厕所,一次只能进一个人,否则会尴尬(出错)。

3.2 临界区的规则

  1. 互斥性:同一时间只能一个进程在临界区
  2. 进入有限等待:不能让进程永远等在外面
  3. 有空让进:临界区空了要允许进程进入

3.3 为什么需要临界区?

回到银行转账例子,"读取余额→修改余额→写回余额"这一段就是临界区,必须保证同一时间只有一个进程执行,否则数据会错乱。

四、信号量的实现与使用

4.1 信号量的核心操作

信号量S是一个整数变量,配合两个操作:

  • P(S):申请资源(Wait操作),相当于"我要拿钥匙"
    • 如果S>0:S减1,成功进入
    • 如果S=0:阻塞等待,直到有人释放资源
  • V(S):释放资源(Signal操作),相当于"还钥匙"
    • S加1,唤醒等待的进程

4.2 用信号量实现互斥(二元信号量)

当信号量S初始化为1时,它就变成了"互斥锁":

// 伪代码:两个进程互斥访问临界区
Semaphore S = 1;  // 初始有1把钥匙

进程A:           进程B:
P(S);            P(S);  // 都想拿钥匙
临界区代码;      临界区代码;
V(S);            V(S);  // 用完还钥匙

原理:S=1时,第一个进程P(S)后S=0,第二个进程P(S)时发现S=0,只能等待;第一个进程V(S)后S=1,第二个进程才能进入。

4.3 用信号量实现同步(计数信号量)

当信号量S初始化为N(N>1)时,它可以控制N个进程同时访问资源:
例子:打印机共享(3台打印机,5个进程使用)

Semaphore printer = 3;  // 初始3把钥匙

进程1:           进程2: ... 进程5:
P(printer);      P(printer);
使用打印机;       使用打印机;
V(printer);      V(printer);

原理:前3个进程P(printer)后,printer从3减到0,第4、5个进程P时会阻塞,直到前3个进程中有人用完还钥匙(V操作)。

五、经典同步问题

5.1 生产者-消费者问题:

问题描述:生产者做面包放到货架,消费者从货架拿面包,货架容量有限(比如只能放10个面包)。

关键点

  • 互斥:同一时间只能一人访问货架(防止面包被抢)
  • 同步:货架满时生产者等待,货架空时消费者等待

信号量解法

Semaphore empty = 10;  // 空位置数量
Semaphore full = 0;    // 满位置数量(初始没面包)
Semaphore mutex = 1;   // 互斥访问货架

生产者:                  消费者:
P(empty);               P(full);
P(mutex);               P(mutex);
放面包到货架;            从货架拿面包;
V(mutex);               V(mutex);
V(full);                V(empty);

逻辑:生产者先看有没有空位置(empty),再拿互斥锁放面包;消费者先看有没有面包(full),再拿互斥锁拿面包。

5.2 读者-写者问题:

问题描述:多个读者可以同时看书,但写者必须独占写书,且写时不能有读者和其他写者。

关键点:读者优先(或写者优先),需要记录读者数量,保证第一个读者来加锁,最后一个读者走解锁。

信号量解法(读者优先):

Semaphore rwlock = 1;   // 读写互斥锁
Semaphore mutex = 1;    // 保护读者计数器的互斥锁
int readcount = 0;      // 读者数量

读者:                    写者:
P(mutex);               P(rwlock);
readcount++;            写数据;
if(readcount == 1) P(rwlock);  // 第一个读者加锁
V(mutex);               V(rwlock);
读数据;
P(mutex);
readcount--;
if(readcount == 0) V(rwlock);  // 最后一个读者解锁
V(mutex);

逻辑:读者来先增加计数器,第一个读者加锁;写者直接加锁,保证独占。

5.3 哲学家就餐问题:

问题描述:5个哲学家围坐一桌,每两人之间有一根筷子,哲学家只能同时拿左右两根筷子才能吃饭,否则思考。

关键点:避免死锁(比如所有人都拿左边筷子,然后等右边筷子,永远吃不上饭)。

避免死锁的解法

  1. 最多允许4个哲学家同时拿筷子(总有一个能吃到)
  2. 规定奇数哲学家先拿左筷子,偶数先拿右筷子(打破循环等待)

信号量解法(方案1):

Semaphore chopstick[5] = {1,1,1,1,1};  // 5根筷子
Semaphore count = 4;                   // 最多4人拿筷子

哲学家i:
P(count);           // 先申请"就餐资格"
P(chopstick[i]);    // 拿左筷子
P(chopstick[(i+1)%5]);  // 拿右筷子
吃饭;
V(chopstick[(i+1)%5]);
V(chopstick[i]);
V(count);           // 释放就餐资格

逻辑:限制同时拿筷子的人数为4,保证至少有一个哲学家能拿到两根筷子。


以上就是对本次关于操作系统博客内容的总结,后续我们将深入探讨操作系统更多知识。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的操作系统博客专栏
https://blog.csdn.net/2402_83322742/category_12916780.html?spm=1001.2014.3001.5482

非常感谢您的阅读,喜欢的话记得三连哦

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到