操作系统-PV
🧠 背景:为什么会有 PV?
类比:内存(生产者) 和 CPU(消费者)
-
内存 / IO / 磁盘 / 网络下载 → 不断“生产数据”
-
例如:读取文件、下载视频、从数据库加载信息
-
-
CPU → 负责“消费数据”
-
例如:处理数据、解码、渲染画面、计算结果
-
👉 由于生产和消费速度可能存在差异(如内存大、CPU处理慢),需要一个缓冲区(如缓存、队列)进行协调。
🔧 三个基本模板
1. 信号量
-
定义:表示当前可用资源的个数。
2. 同步:控制先后顺序
-
核心:信号量初始设为 0;
V
操作释放信号量,进程 B 才能有资源继续执行。 -
问题:如果信号量初始值为 0,进程 A 和进程 B 都会被阻塞吗?
-
回答:是的,这样可以保证进程 A 和 B 的先后顺序。
-
3. 互斥:保证一个进程对资源的访问
-
核心:使用
P
和V
操作夹住临界区(临界资源存放点)。
进程A; mutex=1
P(互斥信号量); mutex--; 0;
临界区;
V(互斥信号量) mutex++; 1;进程B;
P(互斥信号量);
临界区;
V(互斥信号量)
🏭 生产者-消费者模型
✅ full
是什么意思?
-
定义:在生产者-消费者模型中,
full
是一个信号量,用来表示当前缓冲区中“已经存了多少个产品”,也可以理解为“可供消费者消费的数据数量”。
✅ mutex
是什么?
-
定义:
mutex
是 mutual exclusion(互斥)的缩写,表示一次只允许一个线程/进程访问共享资源。用于保护临界区。
🔄 同步与互斥关系
同步关系
-
生产者先生产出一个产品 →
V(full)
,消费者才能消费一个产品 →P(full)
。 -
消费者从缓冲区取来产品 →
V(empty)
,释放一个空位,生产者才能继续生产 →P(empty)
。
互斥关系
-
使用
P(mutex)
加锁缓冲区,V(mutex)
释放缓冲区,确保缓冲区的互斥访问。
❓ 常见问题解答
问题:缓冲区初始为空,empty = n
(如 10 个空位),为什么还需要等待消费者“消费”后产生空位?不是一开始就很多空位了吗?
-
答案:
-
✅ 一开始当然不需要等消费者,可以直接放数据进去!
-
🛑 但如果生产得太快,把缓冲区塞满了(
empty == 0
),就必须等消费者先消费一个产品(释放一个空位)才能继续生产。
-
🧑💻 生产者代码解释
-
生产:在自己线程内处理好数据(不影响别人)。
-
P(empty)
:检查是否有空位(资源控制)。 -
P(mutex)
:进入缓冲区前加锁(互斥控制)。 -
放入缓冲区。
-
V(mutex)
:解锁。 -
V(full)
:通知消费者“有东西可以用了”。
👩💻 消费者代码解释
-
P(full)
:等待是否有产品可取。 -
P(mutex)
:加锁,准备访问缓冲区。 -
取产品:真正的“消费”动作。
-
V(mutex)
:解锁。 -
V(empty)
:通知生产者释放了一个空位。 -
消费:转到自己的线程输出数据。
读者-写者(互斥)
📖 读者-写者问题(互斥)
问题:为什么 mutex
需要夹住 count
,不是允许多个读者同时读吗?
-
回答:是的,多个读者可以同时读,但是
count
是一个“全局变量”,多个线程同时修改它会出问题,所以必须用mutex
来保护它!
🔄 同步与互斥关系
同步关系
-
读者读完后,解锁并将
count--
。当count
为 0 时,表示最后一个读者离开,此时写者可以开始写。 -
简单来说:第一个读者来关写者的门,最后一个读者来开写者的门。
互斥关系:
互斥关系
-
count
的初始值为 0,表示没有读者在读。 -
如果有写者正在写,
rw = 0
,读者会被阻塞,等待写者写完。 -
如果没有写者写,
rw = 1
,第一个读者执行P(rw)
,然后继续执行。
❓ 常见问题解答
问题:如果第一个读者还没执行到 V(mutex)
,第二个读者就进来了,会怎么样?第二个还能继续吗?
-
答案:
-
❌ 第二个读者进不来,它会被阻塞在
P(mutex)
这里,直到第一个读者执行V(mutex)
,它才能继续往下执行。 -
❗ 虽然读者可以“同时读”,但它们更新计数器
count
时一定是串行的、有序的、安全的!
-
ChatGPT链接:https://chatgpt.com/share/680274c9-faec-800c-8a90-253e36512386