进程的互斥方式
1.硬件方式
1)中断禁用
为保证多个并发进程互斥使用临界资源,,需保证一个进程在执行临界区代码时不被中断即可,这个能力可以通过系统内核为启用和禁用中断定又的原语提供,进程可以通过下面的方法实现互斥
2)专用机器指令
CPU的设计者提供了一些硬件指令,用于保证几个动作的原子性。这几个动作在一个指令周期中执行,不会受到其他指令的干扰。
不服从于任何中断,因此可实现进程互斥。
1.硬件方式
1)中断禁用
为保证多个并发进程互斥使用临界资源,,需保证一个进程在执行临界区代码时不被中断即可,这个能力可以通过系统内核为启用和禁用中断定又的原语提供,进程可以通过下面的方法实现互斥
while(1)
{
禁止中断
临界区
启用中断
其余部分
}
由于临界区不能被中断,故可保证互斥。但该方法代价太高,因为CPU被限制于只能交替执行程序,执行效率明显降低
2)专用机器指令
CPU的设计者提供了一些硬件指令,用于保证几个动作的原子性。这几个动作在一个指令周期中执行,不会受到其他指令的干扰。
如testset指令和exchange指令。
testset 指令定义如下:
boolean testset(int i)
{
if(i==0) //如果未被标记则去标记它,并返回true
{
i=1;
return true;
}
else //如果已被标记,则返回false
return false;
}
该指令测试它的参数i的值。如果i为0,则用1取代并返回true.这可以表示临界资源未被使用时,进程占用临界资源;如果i为1,值不变,返回false,,这可以表示临界资源已被使用时,进程不能再占用临界资源。由于整个testset 函数自动整体执行,就是说它
不服从于任何中断,因此可实现进程互斥。
用testset 指令实现互斥举例:
const int n=/*进程数*/;
int bolt; //表示临界资源是否被占用
void P(int i)
{
while(1)
{
while(!testset(bolt))
/*什么也不做*/;
/*临界区*/
bolt=0; //临界资源已释放
/*其余部分*/
}
}
void main()
{
bolt=0;
parbegin(P(1),P(2),...,P(n));
}
每个进程都在循环检测bolt 变量,当bolt 为0时,进程进人临界区;否则进程一直循
exchange 指令定义如下:
void exchange(int register,int memory)
{
int temp;
temp=memory;
memory=register;
register=temp;
}
该指令交换一个寄存器和一个存储器单元的内容。在执行该指令的过程中,任何其他指令对该存储器单元的访问均被阻止。
用exchange 指令实现互斥举例:
const int n=/*进程数*/;
int bolt; //表示临界资源是否被占用
void P(int i)
{
while(1)
{
int key=1;
while(key!=0)
exchange(key,bolt);
/*临界区*/
exchange(key,bolt);
/*其余部分*/
}
}
void main()
{
bolt=0;
parbegin(P(1),P(2),...,P(n));
}
共享变量bolt被初始化为0,每个进程都使用一个局部变量key且初始化为1,唯一可以进入临界区的进程是发现bolt 等于0的那个进程,它把bolt置为1.排斥所有其他进程进人临界区。进程离开临界区时,它把bolt 重置为0,允许另一个进程进人临界区。
机器指令方法具有如下优点。
(1) 适用于在单CPU 或共享主存的多CPU 上的任何数目的进程。
(2) 非常简单且易于证明。
(3) 可用于支持多个临界区。
机器指令方法具有如下缺点。
(1) 使用了忙等待。因此,当一个进程正在等待进人一个临界区时,它会继续消耗CPU 时间。
(2) 可能发生饿死现象。当一个进程离开一个临界区并且有多个进程正在等待时,选择哪一个等待进程是随意的,因此,某些进程可能无限地被拒绝进入。
(3) 可能发生死锁现象。考虑单CPU 中的下列情况: 进程P1执行专门指令并进入临界区,然后P1被中断并把CPU给具有更高优先级的P2。如果P2 试图使用与P1相同的资源,由于互斥机制,它将被拒绝访问。因此,它会进人忙等待循环。但是,由于Pl 比P2 的优先级低,它将永远不会被调度执行。