进程同步
如上图,司机要想启动车辆,必须等待一个信号,
售货员在车关门之后,发送一个信号
- 什么是进程同步?
让进程走走停停来保证多进程合作的合理有序
只是发信号还不能解决全部问题,如下例
- 引入信号量
本来P2也应该被唤醒,所以只是用counter来决定还是不够的,也就是只是发信号还是不够的,需要一个量来记录一些信息,比如上例要记录等待了多少个进程
信号量就是个整形变量
如上图,P进程和C进程就根据信号量sem来决定要不要同步(等待,唤醒)
实现信号量
V的代码在P的基础上修改s.value++,<改为<=即可 - 用信号量解决生产者-消费者问题
mutex是互斥信号量,保证我在写文件时别人都不能写
empty代表空闲资源量
full代表已经装入了的量
信号量临界区保护
信号量必须要正确,不然肯定会出错,乱套
下图的例子会导致信号量错误
是竞争条件,不是编程错误,而是共享数据没有保护造成的竞争错误,你也争我也争,不该争的时候修改了它而导致的错误
- 解决竞争条件
- 引入临界区
那一段代码指的是修改empty的那段代码,p1进入p1的那段代码后,p2不能进入p2的那一段代码
那一段代码就是临界区
读写信号量的代码一定是临界区
所以要想进程能够正确的同步,就得保护它的临界区,保护临界区的核心就是进入区和退出区两段代码,原则是互斥
除了互斥还包括下面两段点
对于进程P0:turn=0才可进入,turn!=0就空转
对于进程P1:turn=1才可进入,turn!=1就空转
上图代码实现了互斥:
p0进入时turn=0,p1不可进入,p0进完后,置turn为1,p1方可进入,p1进入是道理相同
但是未实现有空让进:
p0进完之后置turn=1,但此时p1不需要进入,所以空闲着,此时p0还想进入,因为turn被置位1了,所以没法进入,有空也不能进入
满足了互斥条件:
p0想进入的时候打标记,令flag[0]=true,然后检查p1是否也进入了,如果flag[1]=true说明p1打了标记进入了,那么p0就只能等着,
p0进完之后令flag[0]=0去掉标记
所以满足了互斥
但是还是不满足有空让进的条件:
当p0想进的时候令flag[0]=true,此时调度到了p1,p1也想进,令flag[1]=true,此时p0,p1都打了标记,有空闲,但是谁都不能进去,
满足互斥:
如果p0进入了,说明flag[0]=true,flag[1]=false或turn=0,
flag[0]=true或turn=0使p1进不去,
也就是如果p0,p1都进去了,那么turn就会既等于0也等于1,显然矛盾
所以满足了互斥
满足有空让进:
如果两个都不进,就肯定有个flag=false,有一个flag=false就会有一个进程不自转,进入
满足有限等待:
如果p0请求进入flag[0]=true,后面的p1不可能一直进入,因为p1执行一次,turn就会等于0,p1就会自转
上面的面包店方法是软件方法,太复杂了
引入硬件方法
只有中断才会引起调度,所以阻止调度就可以关中断
cli关中断,sti开中断
上述方法在多核时不好使,因为你只关了1个CPU的中断,只控制了这个CPU不去调度,但是其他CPU还是会调度,你管不了其他CPU
单CPU可以使用这个方法
如果x=false,令x=true,返回false,也就是判断没锁上的同时又加了锁,判断的结果是没锁上所以可以进入,判断的同时又加了锁,阻止其他进程进入