进程间通信
一 竞争条件
两个或多个进程共享同一个内存空间或者同一文件的时候就会发生竞争条件。
二 临界区
防止发生竞争条件的一个方式是使用临界区
我们把访问共享内存或资源的的一段代码称为临界区,如果我们合理安排能够让两个进程不能够同时进入临界区中就可以防止竞争条件
三 忙等待互斥
1 屏蔽中断,
当进程进入临界区后立即屏蔽所有的中断,包括时钟中断。
这样的话就把屏蔽中断的权利交给了进程,这样的话很不安全
另外现在的计算机都是多个cpu了屏蔽了一cpu任然还有很多其他的cpu在运转,这样没有什么用
2 锁变量
就是设置一个共享变量,把这个变量的初始值设置为0,当为0的时候表示没有没有进程访问临界区,当为1的时候表示有进程访问临界区
当一个进程进入临界区的时候要测试这把锁,当为0的时候可以进入,进入后把0设置为1,然后访问临界区,在退出的时候还要把1设置为0
但是这有一个问题,当一个进程发现锁为0,并且在将他设置为1之前另一个进程也访问了所变量,也是0,将它设置为1,当第一个进程再次运行的时候就也把它设置为1,这样的话就会有两个进程同时进入临界区
所以说这招不行
3 严格轮换法
这中方法是设置一个共享变量为turn,初始值为0,假如有两个进程分别为进程0,进程1
当初始值为0的时候进程1 可以访问临界区,当初始值为1的时候进程1可以访问
开始进程0进入临界区,如果此时进程1也想进入临界区,它就会测试turn如果turn为1他就可以进入
,但是此时不为1,所以就进入忙等待,当进程0访问玩临界区后就会把0设置为1,然后进程1就可以进入了
此时进程0向再要进入就不行了,只有等进程1结束之后,把turn设置为0,然后进程0就可以进入了。
这里的问题是,如果说turn为0,则进程已一直进不去,除非是进程0调用一次之后进程1才可以进去,所以说这样的话进程0就阻塞了进程1
如果说进程0比较慢那么进程一则一直等待直到进程0结束,这样也不太好。
4 TSL指令
这是一种硬件支撑的指令,TS Rx,LOCK称为测试并加锁。
它将一个内存字读到寄存器rx中,然后在这个内存地址上存一个非零值,读子和写字的操作时不可分割的。
即该指令结束之前不允许其他处理器访问该内存字,执行TSL指令将锁住内存线,防止其他cpu在本指令结束之前访问该内存
使用TSL指令需要使用一个共享变量lock来对共享内存进行访问
enter_region:
TSL register,Lock
cmp,register,0
JNE enter_region
ret
leave_region
Move lock,0
ret
四 睡眠与唤醒
上边的集中互斥方案都是可以的,但是都有忙等待的缺点,也就是当一个进程想要进入临界区的时候先检查互斥量,如果不被允许就在原地等待,知道允许为止
这种方式浪费了大量的cpu,还会引起其他不必要的问题。
下面是几条通信原语
它们将在无法进入临界区的时候进行阻塞,而不是进行忙等待
sleep函数是将调用该函数的进程睡眠
wakeup有一个参数,能够唤醒另一个进程
生产者与消费者的问题
两个进程共享同一个内存固定的内存区域,一个进程是生产者,另一个进程是消费者。
生产者向内存区域中放入数据项,消费者从内存区域读取数据项,当内存满的时候生产者睡眠,直到消费者从共享内存中读取数据后把它唤醒
当内存区域为空的时候,当消费者向从内存中读取一个数据的时候就会引起自身睡眠,直到生产者放入数据后把它唤醒。
接下来就会发生问题
当消费者发现共享内存中没有数据之后在没有睡眠之前进程切换了,然后生产者进入共享内存,放入数据之后发出一个wakeup信号,但是发现消费者并没有睡着就把信号丢弃了
然后进程切回到消费者,睡眠,接下来消费者就永远不会被唤醒了,最后生产者也睡眠,并且永远不会被唤醒。
1 信号量
信号量用来记录唤醒次数,供以后使用
对信号量设立两种操作down和up分别为(sleep和wakeup)对一个信号量执行down操作的时候,也就是想目标进程发出一个sleep信号的时候,检查信号量
如果信号量大于0的话,信号量减1,否则的话,睡眠
同样,对一个信号量执行一个up操作的时候,也就是想目标进程发出一个wakup操作的时候,如果说有进程在睡眠则唤醒一个进程,信号量的值不发生变化,但是如果说没有进程在睡眠则信号量加1
以上的两种操作中,检查数值,改变数值,唤醒或者睡眠一个进程都是原子操作,也就是不可分割的。在完成该操作之前其他今晨不允许访问该信号量
如果说是单cpu可以使用屏蔽中断,如果说是多个cpu可以是用锁变量或者TSL指令
2互斥量
如果说不需要信号量的计数能力有时可以使用互斥量,0表示解锁,其他值表示加锁,
互斥量非常加单使用TSL指令就可以实现
Mutex_lock:
TSL register,Mutext //将变量锁住
cmp register,0 //与0进行比较
JZE ok //信号量为0,被解锁,返回
call thread_yeild //调度
jmp Mutex_lock //稍后再试
ok:ret //返回调用者进入临界区
Mutex_unlock: //解锁
Move Mutex,0
ret
Mutext_lock与enter_retion的主要区别是Mutext_lock进入缓冲区失败后是调用另一个线程,而enter_region是进入忙等待
浙公网安备 33010602011771号