进程的互斥

并发进程的执行可能是有关的,也可能是无关的。

无关并发进程是指他们分别在不同的变量集合上操作,所以一个进行的执行与其它并发的进程并不会有变量集(值)交集。
有关并发进程是指他们可能共享变量集上的某些变量,如果没有进行PV操作(后面会介绍,暂时挂起),那么可能在同时“存、取、改”操作上产生错误。

针对上面的的共享变量,有一个定义叫"临界区",定义为:有关并发进程中的共享变量有关的程序段

 

临界区/临界资源

一次只允许一个进程使用的资源称为临界资源。为了保证临界资源的正确使用,可以把临界资源的访问过程分成四个部分:进入区->临界区->退出区->剩余区

如何管理临界区正常的运行(也就是上面说的进行“存、取、改”操作不产生错误)呢?
总体概括为这三个要求:互斥性、进展性、有限等待性

互斥性:也就是如果一个进程已经在它的临界区执行,那么其它进程挂起,暂时不能进入该临界区执行;
进展性:如果该进程不在它的临界区执行,那么不应该阻止其他进程进入该临界区执行;
有限等待性:某个进程进入一个临界区应该在有限时间内完成。

 

互斥软件的实现方法

实现方法有三种:标志法、严格轮换法、Peterson算法

标志法: 例如两个进程执行,使用标记来判断他们是否进入了临界区。

缺点:刚好两个进程同时进入各自临界区的情况不能解决。

int inside1, inside2; /* 定义两个标志分别来判断是否进入了临界区 */
inside1 = 0; /* 表示进程P1不在临界区 */
inside2 = 0; /* 表示进程P2不在临界区 */
process P1{
    while(inside2);  /* 如果P2进程在临界区内,那么就等待P2退出临界区 */
    inside1 = 1;  /* 如果P2进程不在临界区,那么P1进入临界区,并进行标志 */
    ...  /* 进入临界区执行 */
    inside1 = 0;  /* 退出临界区,将标志设置为0,表示退出 */
}
process P2{
    while(inside1);  /* 如果P1进程在临界区内,那么就等待P1退出临界区 */
    inside2 = 1;  /* 如果P1进程不在临界区,那么P2进入临界区,并进行标志 */
    ...  /* 进入临界区执行 */
    inside2 = 0;  /* 退出临界区,将标志设置为0,表示退出 */
}

严格轮换法: 使用指针来判断那个程序应该进入临界区。

缺点:造成while循环的忙等待。

int turn;  /* 设置指针turn */
turn = 0; /* 表示进程P0可以进入进程 */
process P0{
    while(turn == 1); /* 如果turn为1,表示此时该是P1进程进入临界区,那么执行等待 */
    ...  /* 如果上面while不等待,那么进入临界区执行 */
    turn = 1;  /* 在进程P0执行完毕就换为进程P1来执行 */
}
process P1{
    while(turn == 0); /* 如果turn为0,表示此时该是P0进程进入临界区,那么执行等待 */
    ...  /* 如果上面while不等待,那么进入临界区执行 */
    turn = 0;  /* 在进程P1执行完毕就换为进程P0来执行 */
}

Peterson算法:是上面两种情况的结合,具体是:先为每个进程设置一个标志,如果标志inside=1表明请求进入进程,然后在使用turn指针表示那个进程进入临界区。

互斥硬件的实现方法

有两种:中断屏蔽方法和硬件指令法

中断屏蔽方法:使进程进入临界区执行,不响应中断,不切换进程。

  好处:简单。缺点:系统代价较高,影响了并发性,无法在多处理器系统中使用。

硬件指令法:测试并设置指令TS;使用Swap指令来管理临界区。

  缺点:同样存在“忙等待”

原文地址:https://www.cnblogs.com/namejr/p/10039210.html