操作系统中的进程同步:读者-写者问题
字数 913 2025-11-17 18:53:09
操作系统中的进程同步:读者-写者问题
问题描述
读者-写者问题(Reader-Writer Problem)是进程同步中的一个经典案例,模拟多个进程并发访问共享数据(如文件、数据库)的场景。其中存在两类角色:
- 读者:只读取数据,不会修改数据,允许多个读者同时访问。
- 写者:会修改数据,必须独占访问,即写者与其他进程(读者或其他写者)互斥。
核心矛盾
- 读者优先:只要有一个读者正在读,后续读者可以直接加入,可能导致写者饥饿。
- 写者优先:一旦写者等待,新读者必须等待写者完成。
- 公平策略:避免任何一方饥饿,按到达顺序调度。
下面以读者优先为例,逐步讲解解决方案。
解决步骤:读者优先方案
1. 分析需要保护的资源与同步关系
- 共享数据:需要被安全访问的目标(如一个数据文件)。
- 读者计数:记录当前正在读的读者数量,需被多个读者进程互斥修改。
- 写者互斥:保证写者独占访问。
2. 定义同步工具
- 互斥锁
rw_mutex:保护读者计数变量(read_count)的修改。 - 写者锁
write_mutex:保证写者独占共享数据,读者和写者共同竞争此锁。
3. 变量初始化
int read_count = 0; // 当前活跃读者数
semaphore rw_mutex = 1; // 保护read_count的互斥锁
semaphore write_mutex = 1; // 控制写者独占的锁
4. 读者进程的逻辑
void reader() {
while (true) {
// 步骤1:获取rw_mutex,安全修改read_count
wait(rw_mutex); // 进入临界区修改read_count
read_count++;
if (read_count == 1) { // 如果是第一个读者,需阻止写者
wait(write_mutex); // 获取写者锁,阻塞写者
}
signal(rw_mutex); // 释放对read_count的保护
// 步骤2:执行读取操作(多个读者可同时进入)
read_data();
// 步骤3:减少读者计数,最后一个读者释放写者锁
wait(rw_mutex);
read_count--;
if (read_count == 0) {
signal(write_mutex); // 允许写者访问
}
signal(rw_mutex);
}
}
关键点解释:
- 第一个读者获取
write_mutex,后续读者直接进入,因为write_mutex已被持有(但未被写者独占)。 - 最后一个读者释放
write_mutex,唤醒可能等待的写者。
5. 写者进程的逻辑
void writer() {
while (true) {
wait(write_mutex); // 申请独占访问权
write_data(); // 执行写操作
signal(write_mutex); // 释放锁
}
}
关键点:写者必须独占 write_mutex,因此会与第一个读者和其他写者互斥。
潜在问题与优化
- 读者优先的缺陷:若读者持续到达,写者可能永远无法获取
write_mutex(饥饿)。 - 写者优先方案:增加一个队列锁,让写者等待时阻塞新读者。
- 公平策略:使用信号量队列(如管程或条件变量)严格按到达顺序调度。
总结
读者-写者问题展示了如何通过信号量协调不同性质的访问需求。核心在于通过计数器管理共享资源的“共享模式”与“独占模式”切换。实际应用中需根据场景选择优先级策略,或使用操作系统提供的高级同步原语(如读写锁 pthread_rwlock_t)直接实现。