为什么要进程同步
生产者消费者问题
了解进程同步之前,先来看这样一个例子,就是著名的生产者消费者模型,
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
上面一段引用是百度百科的解释,大致意思是生产者生产一件商品放在仓库里,仓库的商品count+=1,消费者从仓库中取出一件商品,仓库商品count-=1。
在进程间可以理解为一群生产者进程生产商品提供给消费者进程使用,生产者进程和消费者进程可以并发执行,在两者之间设置一个可容纳n个缓冲区的缓冲池,生产者进程将生产的商品放在缓冲区中,消费者进程可以从缓冲区中取走消费商品。
这个模型在生活中是没有问题的,但是从计算机微观来分析就是存在问题的。在计算机中,缓冲区是在Cache上或主存上的,如果生产者进程或者消费者进程需要操作数据的时候必须分为三个步骤:第一步先把缓冲区的数据取出来放到计算机寄存器里面;第二步把寄存器里的数据+1或者-1,表示生产完成1个产品;第三步需要把这个数据放回到缓冲区里面。
两者并发执行的时候可能会出错,下面将生产者进程和消费者进程并行看待:
假设现在缓冲区内的数据count = 10;
1.执行第一步,生产者进程取出数据register = 10;
2.生产者进程register+=1得到register=11,
3.两个进程并发执行,第三步可能是消费者进程执行,消费者的register=10
4.是消费者进程的第二步,register-=1,消费者寄存器里存9
5.消费者的第三步,把寄存器里的值写入到缓存里,此时两者值都是9,消费者进程完成
6.生产者进程最后一步,把生产者寄存器里的值写入缓冲区,此时的count由9变为11。
这时的答案明显与预期不一致,原本的缓存器值为10,发生+1和-1的操作,此时的缓存器内的值应该还是10。
哲学家进餐问题
关于这个问题的描述摘自百度
有五个哲学家,他们的生活方式是交替地进行思考和进餐,哲学家们共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五支筷子,平时哲学家进行思考,饥饿时便试图取其左、右最靠近他的筷子,只有在他拿到两支筷子时才能进餐,该哲学家进餐完毕后,放下左右两只筷子又继续思考。
约束条件
(1)只有拿到两只筷子时,哲学家才能吃饭。
(2)如果筷子已被别人拿走,则必须等别人吃完之后才能拿到筷子。
(3)任一哲学家在自己未拿到两只筷子吃完饭前,不会放下手中已经拿到的筷子。
哲学家吃饭的过程有三步:
1.拿起左边的筷子
2.拿起右边的筷子
3.吃饭
假设某一个哲学家饿了,它拿起了左边的筷子,发现右边筷子被拿了,他只能等待右筷子被释放,拿到右筷子后进餐。
在极端的情况下,如果这五个哲学家同时拿起了左筷子,他们都需要等待右筷子的释放,因为他们进餐后才能释放,最终他们拿不到右筷子而全部饿死。
发生上述两个问题的根源: 进程彼此之间没有通信,如果生产者通知了消费者我已经生产好了一件商品,或者哲学家告诉旁边的人我准备进餐了,别动我的筷子,这样就不会发生上述问题。
因此需要进程间的同步:
1.解决对竞争资源在多个进程间进行使用次序的协调
2.使得并发执行的进程之间可以有效的使用资源并相互合作
进程同步原则
临界资源指的是一些虽然作为共享资源但又无法同时被多个线程共同访问的共享资源。 当有进程在使用临界资源时,其他进程必须依据操作系统的同步机制等待占用资源的进程释放资源才能重新竞争使用。比如上述例子中的筷子和商品。
为了对临界资源进行有效的约束,提出了进程间同步的四个原则:
- 空闲让进:临界资源如果没有被占用,操作系统允许某一进程使用临界资源
- 忙则等待:如果资源有进程占用,这时应该防止需要使用资源的进程继续使用资源,而应该让其他请求进程,等待资源被释放
- 有限等待:在忙则等待的基础上,临界资源被占用,也要保证别的需要使用资源等待的进程能够在有限的时间内使用资源,以避免等待进程僵时等待
- 让权等待:外面需要等待的进程等待时,进程应该让出CPU的使用权,进程从运行状态变为阻塞状态。
进程间同步的方法:
1.消息队列
2.共享存储
3.信号量
线程同步
在多线程并发使用进程资源的时候同样也会发生生产者消费者问题和哲学家进餐问题,因此进程间的多线程也需要同步。
线程同步的方法:
- 互斥量:多线程可以互斥的使用临界资源的一个锁
- 读写锁:应对多读少写,或者多写少读的情况
- 自旋锁
- 条件变量