三个进程同步问题---(生产者-消费者,哲学家进餐,读者-写者)

一:生产者-消费者问题(Producer-Consumer Problem)
 
问题描述
 
- 场景:多个生产者进程向缓冲区投放数据,消费者进程从中取出数据,缓冲区大小固定(如n个槽位)。
 
- 核心矛盾:
 
- 互斥:同一时刻只能有一个进程访问缓冲区(临界资源)。
 
- 同步:生产者需等待缓冲区未满,消费者需等待缓冲区非空。
 
关键解决方案(信号量机制)
 
1. 信号量定义:
 
-  mutex :互斥信号量,初值为1,保证对缓冲区的互斥访问。
 
-  empty :同步信号量,初值为 n (缓冲区空槽数),控制生产者能否放入数据。
 
-  full :同步信号量,初值为0(缓冲区数据项数),控制消费者能否取出数据。
 
2. 生产者代码逻辑:


while (1) {
    生产数据item;
    wait(empty);    // 等待空槽位
    wait(mutex);    // 互斥访问缓冲区
    将item放入缓冲区;
    signal(mutex);  // 释放互斥锁
    signal(full);   // 通知消费者有数据可用
}


  
3. 消费者代码逻辑:

 
while (1) {
    wait(full);     // 等待数据可用
    wait(mutex);    // 互斥访问缓冲区
    从缓冲区取出数据item;
    signal(mutex);  // 释放互斥锁
    signal(empty);  // 通知生产者有空槽位
}


考点延伸
 
- 变种:单缓冲区(无需 mutex ,仅需 empty 和 full )、多生产者-多消费者。
生产者-消费者单缓冲区问题
 
问题描述:
 
- 缓冲区大小为1(仅能存放1个数据),生产者每次生产一个数据放入缓冲区,消费者每次从缓冲区取出一个数据。
 
- 核心矛盾:
 
- 缓冲区为空时,消费者需等待;缓冲区为满时,生产者需等待。
 
- 单缓冲区无需考虑互斥(同一时刻只能有一个进程访问),仅需解决同步问题。


- 易错题点:信号量顺序(先同步后互斥,避免死锁)。
 
二、读者-写者问题(Readers-Writers Problem)
 
问题描述
 
- 场景:共享数据可被多个读者同时读取,但写者必须独占访问(读写互斥、写写互斥)。
 
- 核心矛盾:
 
- 第一类读者-写者问题:优先保证读者,可能导致写者饥饿。
 
- 第二类读者-写者问题:优先保证写者,减少写者等待时间。
 
关键解决方案(信号量机制)
 
第一类读者-写者(读者优先)
 
1. 信号量定义:
 
-  read_count :记录当前读者数,初值为0,需用 mutex 互斥保护。
 
-  mutex :保护 read_count 的互斥信号量,初值为1。
 
-  write_lock :读写互斥信号量,初值为1(写者获取锁,读者仅在无写者时读取)。
 
2. 读者代码逻辑:

 
wait(mutex);          // 互斥访问read_count
if (read_count == 0)  
    wait(write_lock); // 第一个读者需阻塞写者
read_count++;        
signal(mutex);        // 释放互斥锁
读取数据;  
wait(mutex);          // 互斥访问read_count
read_count--;        
if (read_count == 0)  
    signal(write_lock); // 最后一个读者释放写锁
signal(mutex);        // 释放互斥锁


 
 
3. 写者代码逻辑:


wait(write_lock); // 阻塞所有读者和写者
写入数据;  
signal(write_lock); // 释放写锁


 
 
第二类读者-写者(写者优先)
 
- 核心修改:增加一个信号量 wrt 表示写者是否等待,读者需检查是否有写者等待才能进入。
 
考点延伸
 
- 核心区别:两类问题的公平性差异,需掌握信号量增减逻辑。
 
- 适用场景:读多写少场景用读者优先,写多读少用写者优先。
 
三、哲学家就餐问题(Dining Philosophers Problem)
 
问题描述
 
- 场景:n个哲学家围坐餐桌,每人需交替“思考”和“就餐”,就餐时需同时获得左右两根筷子(资源),筷子总数等于哲学家数(每根筷子被两人共享)。
 
- 核心矛盾:若所有哲学家同时拿左侧筷子,会导致死锁(循环等待资源)。
 
关键解决方案
 
1. 避免死锁的策略:
 
- 策略1:限制同时就餐人数
 
- 用信号量 sm 限制最多 n-1 个哲学家同时拿筷子,确保至少1人不抢筷,打破循环等待。
 
- 策略2:奇数拿左筷,偶数拿右筷
 
- 强制部分哲学家先拿右筷,避免统一方向的资源竞争。
 
- 策略3:仅当两根筷子都可用时才拿取
 
- 用信号量数组 chopstick[5] 表示筷子,哲学家拿筷前先检查左右是否可用(需互斥访问状态数组)。
 
2. 基于信号量的代码示例(策略1):


semaphore chopstick[5] = {1,1,1,1,1}; // 筷子信号量
semaphore sm = n-1;                  // 限制就餐人数
void philosopher(int i) {
    while (1) {
        think();
        wait(sm);          // 等待可用就餐名额
        wait(chopstick[i]); // 拿左筷
        wait(chopstick[(i+1)%5]); // 拿右筷
        eat();
        signal(chopstick[i]); // 放左筷
        signal(chopstick[(i+1)%5]); // 放右筷
        signal(sm);          // 释放就餐名额
    }
}


 
 
考点延伸
 
- 死锁必要条件:本题是“循环等待”的典型案例,解决方案需针对死锁条件(如破坏循环等待或请求与保持)。
 
- 易错题点:未考虑筷子的互斥性(每根筷子只能被一人使用),需用信号量正确表示资源。
 
考研复习要点总结
 
1. 核心能力:
 
- 熟练用信号量( wait/signal )实现互斥与同步,区分互斥信号量(初值1)和同步信号量(初值非1)。
 
- 分析问题中的临界资源、同步关系(如“前操作未完成,后操作需等待”)。
 
2. 答题模板:
 
- 明确信号量含义及初值 → 编写进程代码 → 验证是否解决互斥/同步问题 → 分析是否存在死锁/饥饿。
 
3. 真题方向:
 
- 变种问题(如带缓冲区的读者-写者、多桌哲学家),需灵活调整信号量逻辑。

你可能感兴趣的:(计算机操作系统,计算机操作系统,进程同步问题)