一、要解决的问题:
- 如何把信息由一个进程传递给另外一个进程
- 如何处理两个或多个进程在临界区的问题
- 两个进程或多个进程的顺序问题(如何实现同步)
二、基本概念:
2.1竞争条件: 两个或多个进程读写某些共享数据时,最后的结果取决于进程运程运行的精确时序。(说到底,是访问临界资源时,a进程先访问一半时,a进程被阻塞,b进程去运行,也到了临界资源,把a的之前已经运行了的半个临界资源数据覆盖了,则下一次a在运行时,根据先前的临界区的值,就有了错误的执行结果)
2.2临界区: 为了避免竞争条件,也就是互斥访问共享资源(一个进程在使用另一个进程不得使用)。而临界区是程序片段,什么样的程序片呢?访问共享内存的程序片段。互斥即:是两个进程不同时在临区
避免竞争条件的四个条件:
- 任何两个进程不的同时处于临界区(竞争条件)
- 不应对cpu的速度和数量做任何假设(这个我自己理解为通过程序代码和运算速度,人可以猜测进入临界区的时间,让另外一个进程等待完这个时间后手动进入临界区,但这样是不可以的,必须把进入临界区的时间交给操作系统管理)
- 临界区外的进程不的阻塞其他进程(没有共享资源的约束,进程间不得以任何方式阻塞对方)
- 不的使进程无限期等待进入临界区(进程不能无限被阻塞)
三、忙等待互斥(几种互斥):
3.1屏蔽中断:单个处理器,每个进程刚进入临界区就把中断屏蔽了,在离开时打开。由于时钟中断屏蔽了,cpu不会发生进程间的切换,那么这个进程可以一直使用cpu,临界区。
问题:把中断控制权交给用户不安全。另一点是多处理器,一个cpu屏蔽中断,另外一个cpu是不会被屏蔽的。
3.2锁变量:设置一个共享锁变量,开始为零,进入为改变1,出来改变为0。这个一听就有问题,用一个共享变量去保护另一个共享资源,那么这个共享变量怎么保护?所以这个互斥是不行的。
3.3严格轮换法:这个也有一个变量turn(初始0),用于记录轮到哪一个进入临界区了。一个进程是当是0的时候进入,另一个是1的时候进入,当一个进程进入,另外一个进程不停的循环检查turn的值,知道turn改变才进入,这个循环检查就是忙等待,极为浪费cpu时间,只有在等待时间很短的时候,才用忙等待,当一个进程频繁进入临界区,另一个进程不频繁时,用严格轮换法,两个进程你一次我一次的进入,这样进入临界区频繁的进程就会被其他围在临界区的进程阻塞,违反了之前的条件。
3.4Peterson解法:
#define N 2//两个进程
int turn;
int interested[N];
void enter_region(int process)
{
int other;
other=1-process;
interseted[process]=TRUE;
turn=process;
while(turn==process && interseted[other] == TRUE);
}
void leave_region(int process)
{ interested[process]=FALSE;
}
turn表示轮到谁进入临界区了,数组代表了那一个进程想进入临界区。只有另外一个进程不想进临界区,我就能进入(interseted[other]==FALSE)或者轮到我的时候另外一个进程也想进入临界区时,我先进入而另外一个在等待我出来(turn==1-process)(解决了两个几乎同时进入的情况)。
3.5TSL指令: 硬件实现。TSL RX,LOCK语句,测试并加锁,将一个内存字lock读入寄存器RX,猴后再lock上存一个非零值,读写不可分割:该指令结束前其他处理器不可以访问内存字,采用锁住总线的方式(与屏蔽中断不同)。前面有点啰嗦,简单点说:同锁变量类似,一个共享变量lock存入register中,register的值为零则可进入,为1不可进入,忙等待检测是否为0,另一个进入操作结束时,变为0;