进程同步的概念
主要任务
➢ 使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性。
进程间的制约关系
➢ 间接相互制约关系(互斥关系)
• 进程互斥使用临界资源
➢ 直接相互制约关系(同步关系)
• 进程间相互合作
临界资源
➢ 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源或共享变量。
➢ 诸进程间应采取互斥方式,实现对这种资源的共享。
➢ 同步——指两个事件的发生有着某种时序上的关系(先,后)
➢ 互斥——资源的使用要排它使用,防止竞争冲突(不同时使用,但无先后次序) (作为一种特殊同步)
➢ 临界区:进程中涉及临界资源的代码段
➢ 进入区:用于检查是否可以进入临界区的代码段。
➢ 退出区:将临界区正被访问的标志恢复为未被访问标志。
➢ 剩余区:其他代码
软件同步机制
turn:哪个进程可以进入临界区
flag:哪个进程想要进入临界区
硬件同步机制
信号量机制
信号量-软件解决方案:
➢ 保证两个或多个代码段不被并发调用
➢ 在进入关键代码段前,进程必须获取一个信号量,否则不能运行
➢ 执行完该关键代码段,必须释放信号量
➢ 信号量有值,为正说明它空闲,为负说明其忙碌
信号量只能通过初始化和两个标准的原语PV来访问--作为OS核心代码执行,不受进程调度的打断
初始化指定一个非负整数值,表示空闲资源总数(又称为"资源信号量")--若为非负值表示当前的空闲资源数,若为负值其绝对值表示当前等待临界区的进程数
在记录型信号量中,wait或signal仅能对某类临界资源进行一个单位的申请和释放,当需要对N个单位进行操作时,需要N次wait/signal操作,效率低下
管程机制
➢ 一个管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据
条件变量的操作
➢ 阻塞操作:wait
➢ 唤醒操作:signal
x.wait(): 进程阻塞直到另外一个进程调用x.signal()
x.signal():唤醒另外一个进程
经典进程的同步问题
生产者-消费者问题
➢ 生产者(M个):生产产品,并放入缓冲区
➢ 消费者(N个):从缓冲区取产品消费
哲学家进餐问题
五个哲学家的生活方式:交替思考和进餐
共用一张圆桌,分别坐在五张椅子上
在圆桌上有五个碗和五支筷子
平时哲学家思考,饥饿时便试图取用其左、右最靠近他的筷子,只有在拿到两支筷子时才能进餐
进餐毕,放下筷子又继续思考
可能引起死锁,如五个哲学家同时饥饿而各自拿起左筷子时,会使信号量chopstick均为0;因此他们试图去拿右筷子时,无法拿到而无限期等待
解决方法:
① 最多允许4个哲学家同时坐在桌子周围
② 仅当一个哲学家左右两边的筷子都可用时,才允许他拿筷子。
③ 给所有哲学家编号,奇数号的哲学家必须首先拿左边的筷子,偶数号的哲学家则反之
读者-写者问题
如果读者来:
◼ 无读者、写者,新读者可以读。
◼ 有写者等,但有其它读者正在读,则新读者也可以读。
◼ 有写者写,新读者等。
如果写者来:
◼ 无读者,新写者可以写。
◼ 有读者,新写者等待。
◼ 有其它写者,新写者等待。
死锁 :两个或多个进程无限期地等待一个事件的发生,而该事件正是由其中的一个等待进程引起的。
饥饿 :无限期地阻塞,进程可能永远无法从它等待的信号量队列中移去。
信号量同步的缺点
Linux并发的主要来源: 中断处理、内核态抢占、多处理器的并发。