当前位置: 首页 > ai >正文

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

计算机操作系统(十五)互斥锁,信号量机制与整型信号量

  • 前言
  • 一、进程同步问题
    • 1.1 什么是进程?
    • 1.2 为什么需要同步?
  • 二、从信号到信号量
    • 2.1 什么是信号?
    • 2.2 信号量的诞生
  • 三、临界区:不能多人同时进的"小房间"
    • 3.1 什么是临界区?
    • 3.2 临界区的规则
    • 3.3 为什么需要临界区?
  • 四、信号量的实现与使用
    • 4.1 信号量的核心操作
    • 4.2 用信号量实现互斥(二元信号量)
    • 4.3 用信号量实现同步(计数信号量)
  • 五、经典同步问题
    • 5.1 生产者-消费者问题:
    • 5.2 读者-写者问题:
    • 5.3 哲学家就餐问题:


前言

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

我的个人主页,欢迎来阅读我的其他文章
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

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

在这里插入图片描述

http://www.xdnf.cn/news/14581.html

相关文章:

  • 安全版V4.5密码加密算法由SM3改为MD5
  • 使用Windows自带的WSL安装Ubuntu Linux系统
  • SQLite FTS4全文搜索实战指南:从入门到优化
  • Java基础(三):逻辑运算符详解
  • 【技术分享】XR技术体系浅析:VR、AR与MR的区别、联系与应用实践
  • 从语言到生态:编程语言在各行业的应用格局与未来演进
  • 考研408《计算机组成原理》复习笔记,第三章(1)——存储系统概念
  • CMCC RAX3000M nand版 OpenWrt 可用空间变小的恢复方法
  • redis相关面试题
  • 使用模板创建uniapp提示未关联uniCloud问题
  • vscode+react+ESLint解决不引入组件,vscode不会报错的问题
  • 小孙学变频学习笔记(四)变频器的逆变器件—IGBT管(下)
  • linux 远程终端执行qt应用显示到接入的物理显示器上
  • 如何仅用AI开发完整的小程序<5>—让AI制作开始页面
  • C++ Programming Language —— 第2章:数据类型
  • C#.NET HttpClient 使用教程
  • 【Dicom标准】dicom数据中pixelData显示处理流程详细介绍
  • Linux 服务器运维:磁盘管理与网络配置
  • 一个免费的视频、音频、文本、图片多媒体处理工具
  • ICM-20948 Wake on Motion功能开发全过程(8)
  • Python 的内置函数 hash
  • python模块常用语法sys、traceback、QApplication
  • 操作系统内核态和用户态--2-系统调用是什么?
  • 决策树:化繁为简的智能决策利器
  • GO语言---数组
  • 【Docker基础】Docker镜像管理:docker rmi、prune详解
  • 经典:在浏览器地址栏输入信息到最终看到网页的全过程,涉及网络协议以及前后端技术
  • Vue状态管理实践:使用Vuex进行前端状态管理
  • FVISION 未来视界工作室:AI驱动的创新与智能外包平台
  • TodoList 案例(Vue3): 使用Composition API