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

操作系统-PV

🧠 背景:为什么会有 PV?

类比:内存(生产者) 和 CPU(消费者)

  • 内存 / IO / 磁盘 / 网络下载 → 不断“生产数据”

    • 例如:读取文件、下载视频、从数据库加载信息

  • CPU → 负责“消费数据”

    • 例如:处理数据、解码、渲染画面、计算结果

👉 由于生产和消费速度可能存在差异(如内存大、CPU处理慢),需要一个缓冲区(如缓存、队列)进行协调。

🔧 三个基本模板

1. 信号量

  • 定义:表示当前可用资源的个数。

2. 同步:控制先后顺序

  • 核心:信号量初始设为 0;V 操作释放信号量,进程 B 才能有资源继续执行。

  • 问题:如果信号量初始值为 0,进程 A 和进程 B 都会被阻塞吗?

    • 回答:是的,这样可以保证进程 A 和 B 的先后顺序。

3. 互斥:保证一个进程对资源的访问

  • 核心:使用 PV 操作夹住临界区(临界资源存放点)。

进程A;                 mutex=1
P(互斥信号量);        mutex--;   0;
临界区;                
V(互斥信号量)          mutex++;   1;进程B;               
P(互斥信号量);      
临界区;                
V(互斥信号量)       

🏭 生产者-消费者模型

full 是什么意思?

  • 定义:在生产者-消费者模型中,full 是一个信号量,用来表示当前缓冲区中“已经存了多少个产品”,也可以理解为“可供消费者消费的数据数量”。

mutex 是什么?

  • 定义mutex 是 mutual exclusion(互斥)的缩写,表示一次只允许一个线程/进程访问共享资源。用于保护临界区。

🔄 同步与互斥关系

同步关系

  1. 生产者先生产出一个产品V(full),消费者才能消费一个产品 → P(full)

  2. 消费者从缓冲区取来产品V(empty),释放一个空位,生产者才能继续生产 → P(empty)

互斥关系

  • 使用 P(mutex) 加锁缓冲区,V(mutex) 释放缓冲区,确保缓冲区的互斥访问。

❓ 常见问题解答

问题:缓冲区初始为空,empty = n(如 10 个空位),为什么还需要等待消费者“消费”后产生空位?不是一开始就很多空位了吗?

  • 答案

    • ✅ 一开始当然不需要等消费者,可以直接放数据进去!

    • 🛑 但如果生产得太快,把缓冲区塞满了(empty == 0),就必须等消费者先消费一个产品(释放一个空位)才能继续生产。

🧑‍💻 生产者代码解释

  1. 生产:在自己线程内处理好数据(不影响别人)。

  2. P(empty):检查是否有空位(资源控制)。

  3. P(mutex):进入缓冲区前加锁(互斥控制)。

  4. 放入缓冲区

  5. V(mutex):解锁。

  6. V(full):通知消费者“有东西可以用了”。

👩‍💻 消费者代码解释

  1. P(full):等待是否有产品可取。

  2. P(mutex):加锁,准备访问缓冲区。

  3. 取产品:真正的“消费”动作。

  4. V(mutex):解锁。

  5. V(empty):通知生产者释放了一个空位。

  6. 消费:转到自己的线程输出数据。

读者-写者(互斥)

📖 读者-写者问题(互斥)

问题:为什么 mutex 需要夹住 count,不是允许多个读者同时读吗?

  • 回答:是的,多个读者可以同时读,但是 count 是一个“全局变量”,多个线程同时修改它会出问题,所以必须用 mutex 来保护它!

🔄 同步与互斥关系

同步关系

  • 读者读完后,解锁并将 count--。当 count 为 0 时,表示最后一个读者离开,此时写者可以开始写。

  • 简单来说:第一个读者来关写者的门,最后一个读者来开写者的门。

互斥关系:

互斥关系

  • count 的初始值为 0,表示没有读者在读。

  • 如果有写者正在写,rw = 0,读者会被阻塞,等待写者写完。

  • 如果没有写者写,rw = 1,第一个读者执行 P(rw),然后继续执行。

❓ 常见问题解答

问题:如果第一个读者还没执行到 V(mutex),第二个读者就进来了,会怎么样?第二个还能继续吗?

  • 答案

    • ❌ 第二个读者进不来,它会被阻塞在 P(mutex) 这里,直到第一个读者执行 V(mutex),它才能继续往下执行。

    • ❗ 虽然读者可以“同时读”,但它们更新计数器 count 时一定是串行的、有序的、安全的!

相对写优先(有限)

设置P(w)V(w):

1:当读进程先来时候,执行P(W),W=0,写进程堵塞,只有当读进程释放了,写进程才能进来。

2:当写进程先来时候,执行P(W),W=0,读进程堵塞,只有当写进程释放了,读进程才能进来。

哲学家用餐(都会有几率导致死锁)

限制n-1哲学家就餐

使用信号量(semaphore count=4)限制同时就餐的哲学家数量为4个,理论上想避免所有5个哲学家同时拿筷子。但如果4个哲学家分别拿了一根筷子(例如,0号拿0筷子,1号拿1筷子,依此类推),第5个哲学家无法进入就餐,而已进入的4个哲学家仍在等待另一根筷子,依然会死锁。

仅当左右筷子可用时候,才会吃饭。

使用mutex紧紧夹住拿筷子的动作

每个哲学家都先试图拿左筷子(P(chopsticks[i])),再拿右筷子(P(chopsticks[(i+1)%5]))。如果所有哲学家同时拿左筷子,就会形成循环等待(每个人都拿着一根筷子,等待另一根),导致死锁。

奇数号先拿左筷子。偶数号拿右筷子

哲学家编号为:1 ~ 5,筷子编号也为 1 ~ 5

每位哲学家要吃饭,必须拿 左手边和右手边的筷子

  • 哲学家 i 的左手筷子编号:i

  • 哲学家 i 的右手筷子编号: (i % 5) + 1

这里试图通过让一个哲学家(if(i%2==0))先拿左筷子,其他人先拿右筷子来打破对称性。但如果所有哲学家同时进入循环,依然可能出现循环等待。例如,编号为偶数的哲学家拿左筷子,编号为奇数的拿右筷子,最终还是会形成死锁。

ChatGPT链接:https://chatgpt.com/share/680274c9-faec-800c-8a90-253e36512386


http://www.mrgr.cn/news/98929.html

相关文章:

  • RHCE的简单配置
  • QT调用ffmpeg库实现视频录制
  • MMAction2安装
  • Windows 部署 DeepSeek 详细教程
  • 基于Ubuntu22.04和OpenCV4.5.4的物联网人脸识别考勤机
  • 前端:uniapp框架中<scroll-view>如何控制元素进行局部滚动
  • Gnome将默认终端设置为 Kitty
  • 鸿蒙语言基础
  • 【深度学习】【目标检测】【Ultralytics-YOLO系列】YOLOV3核心文件yolo.py解读
  • 贪心、动态规划、其它算法基本原理和步骤
  • DevOps-文章目录
  • 树上启发式合并 系列 题解
  • 5.0.2 颜色16进制格式含义 控件template中path的使用
  • 图像预处理-图像噪点消除
  • 告别Feign:基于Spring 6.1 RestClient构建高可用声明式HTTP客户端
  • Qt 入门 5 之其他窗口部件
  • transformer-词嵌入和位置嵌入详解
  • 线程池七个参数的含义
  • fastdds:传输层SHM和DATA-SHARING的区别
  • 【MySQL】MySQL表的增删改查(CRUD) —— 上篇