2.5 经典进程的同步问题
L10
学习目标
生产者-消费者与哲学家进餐:用信号量/互斥在内核侧协调。验收程序在 user/,机制在 los_sem.c / los_mux.c。
- 生产者-消费者问题:生产者生产数据放入缓冲区,消费者从缓冲区取数据;需用 wait/signal 操作协调,设置互斥信号量和资源信号量。
- 哲学家进餐问题:五个哲学家共享五根筷子,需避免死锁和饥饿;统一加锁顺序可预防死锁。
- 经典同步问题的核心:利用信号量机制解决进程间的制约关系,保证并发执行的正确性。
原理 · 深入理解
2.5 经典进程的同步问题
本节概览:先建立「经典进程的同步问题」的框架,再依次展开下列小节。
- 生产者-消费者问题
- 哲学家进餐问题
- 读者-写者问题
2.5.1 生产者-消费者问题
本节通过三个经典例子阐述进程同步:生产者-消费者、哲学家进餐、读者-写者。
它们分别对应资源争用、循环等待、读写共享三类典型问题,是后续各种同步机制的样板。
- 哲学家进餐问题
- 读者-写者问题
对于生产者-消费者问题,也可利用AND信号量来解决,即用Swait(empty,mutex)来代替wait(empty)和wait(mutex);用Ssignal(mutex,full)来代替signal(mutex)和signal(full);用Swait(full,mutex)代替wait(full)和wait(mutex),以及用Ssignal(mutex,empty)代替Signal(mutex)和Signal(empty)。
2.利用AND信号量解决生产者-消费者问题。
在利用管程方法来解决生产者-消费者问题时,首先便是为它们建立一个管程,并命名为procducerconsumer,或简称为PC。其中包括两个过程。
- put(x)过程
- get(x)过程。 对于条件变量notfull和notempty,分别有两个过程cwait和csignal对它们进行操作:
仍存在下述问题。
- cwait(condition)过程:当管程被一个进程占用时,其他进程调用该过程时阻塞,并挂在条件condition的队列上
- csignal(condition)过程:唤醒在cwait执行后阻塞在条件condition队列上的进程,如果这样的进程不止一个,则选择其中一个实施唤醒操作;如果队列为空,则无操作而返回
- PC管程描述如下。
2.5.2 哲学家进餐问题
本节通过三个经典例子阐述进程同步:生产者-消费者、哲学家进餐、读者-写者。
它们分别对应资源争用、循环等待、读写共享三类典型问题,是后续各种同步机制的样板。
- 生产者-消费者问题
- 读者-写者问题
- 上述解法保证不会有两个相邻的哲学家同时进餐,却可能引起死锁。 解决方式:
- 仅当哲学家的左右两只筷子均可用时,才允许他拿起筷子进餐
- 规定奇数号哲学家先拿他左边的筷子,再拿右边的筷子;偶数号哲学家则相反
至多允许四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕时能释放出他用过的两只筷子,从而使更多的哲学家能够进餐
利用AND信号量机制解决哲学家进餐问题
在哲学家进餐问题中,要求每个哲学家先获得两个临界资源(筷子)后方能进餐,这在本质上就是前面所介绍的AND同步问题,故用AND信号量机制可获得最简洁的解法。
Semaphore chopstick chopstick[5] = {1,1,1,1,1}; Do{ … //think Sswait(chopstick[(i+1)%5],chopstick[i]); … //eat … Ssignal(chopstick[(i+1)%5],chopstick[i]); }while[TRUE]。
2.5.3 读者-写者问题
本节通过三个经典例子阐述进程同步:生产者-消费者、哲学家进餐、读者-写者。
它们分别对应资源争用、循环等待、读写共享三类典型问题,是后续各种同步机制的样板。
- 生产者-消费者问题
- 哲学家进餐问题
这里的读者—写者问题增加了一个限制,即最多只允许RN个读者同时读。为此,又引入了一个信号量L,并赋予其初值为RN,通过执行wait(L, 1, 1)操作来控制读者的数目,每当有一个读者进入时,就要先执行wait(L, 1, 1)操作,使L的值减1。
当有RN个读者进入读后,L便减为0,第RN + 1个读者要进入读时,必然会因wait(L, 1, 1)操作失败而阻塞。
2.利用信号量集机制解决读者-写着问题。
做 · 实验
- 打开工作台 L10,对照 los_mux.c(哲学家)与可选 07-sem(产消)。
- 烧录 16-classic,A/B 交替 think/eat 且能结束。
- 选做:烧录 07-sem,串口 P:0 C:0 … 成对出现。
- 根据「学习目标」列出 3 个关键词,对照原理段落解释给自己听。
经典进程的同步问题
rms-edf
用控件单步操作;日志区记下每一步发生了什么。
代码导读
本课在工作台编译烧录。先读 user 实验入口,再对照 kernel / HDF 中被调用的函数,不要一上来改链接脚本。
总结与提升
- 无共享缓冲破坏;能对照理论图讲解日志。
- 能默写产消信号量初值,并能说明本课为何先拿小号叉。
- 能用自己的话复述学习目标,并指出概念与板上实验的对应。
延伸思考
- 若两人各先拿自己左边的叉,会怎样?
- 如果把本节机制拿到 Linux 或完整 OpenHarmony 上,会多出哪些硬件假设?