硬件同步

在同步硬件中,我们使用从硬件到应用程序程序员可用的基于软件的API的技术探索针对临界区问题的更多解决方案。这些解决方案基于锁定的前提;但是,这种锁的设计可能非常复杂。

这些硬件功能可以使任何编程任务更加轻松,并提高系统效率。在这里,我们介绍了一些可在许多系统上使用的简单硬件说明,并说明了如何有效地使用它们来解决临界区问题。如果我们可以防止在修改共享变量时发生中断。临界区问题可以简单地在单处理器环境中解决。以这种方式,我们将确保当前的指令序列将被允许按顺序执行而无需抢占。将不会运行其他指令,因此不会对共享变量进行意外修改。这是非抢先内核采用的方法。但是不幸的是,这种解决方案在多处理器环境中并不可行。

当此消息传递延迟进入每个关键部分时,系统效率会降低。如果时钟通过中断保持更新,那么也会考虑对系统时钟的影响。因此,许多现代计算机系统提供了特殊的硬件指令,这些指令使我们能够测试和修改单词的内容,或者原子地交换两个单词的内容,即作为一个不间断的单元。我们可以使用这些特殊说明以相对简单的方式解决关键部分的问题。现在,我们抽象出这些类型的指令背后的主要概念。 TestAndSet()指令可以被定义为示于下面的代码。

boolean test and set(boolean *target){
   boolean rv = *target;
   *target = true;
   return rv;
}

测试和set()说明的定义。

基本特征是该指令是原子执行的。因此,如果同时执行两条TestAndSet C)指令(每条指令在不同的CPU上),它们将以任意顺序顺序执行。如果机器支持TestAndSet()指令,我们可以通过声明一个初始化为false的布尔变量锁来实现互斥。过程P的结构如下所示。

示例

do {
   while (test and set(&lock)) ;
   /* do nothing */
   /* critical section */
   lock = false;
   /* remainder section */
}
while (true);

使用test和的互斥实现set()

与TestAndSet0指令相反,SwapO指令对两个字的内容进行操作;它是原子执行的。如果机器支持SwapO指令,则可以按以下方式提供互斥。在此,声明了全局布尔变量锁并将其初始化为false。此外,每个进程都有一个本地布尔变量键。过程P的结构如下图所示。

int compare_and_swap(int *val, int expected, int new val){
   int temp = *val;
   if (*val == expected)
   *val = new val;
   return temp;
}

比较和swap()指令的定义。

do{
   while (compare_and_swap(&lock, 0, 1) != 0) ;
   /* do nothing */
   /* critical section */
   lock = 0;
   /* remainder section */
}
while (true);

具有比较和swap()指令的互斥实现。

由于这些算法满足互斥要求,因此不满足有界等待条件。在下面的代码中,我们使用TestAndSet()满足所有关键部分要求的指令介绍了另一种算法。

do{
   waiting[i] = true;
   key = true;
   while (waiting[i] && key)
      key = test and set(&lock);
   waiting[i] = false;
   /* critical section */
   j = (i + 1) % n;
   while ((j != i) && !waiting[j])
      j = (j + 1) % n;
   if (j == i)
      lock = false;
   else
      waiting[j] = false;
   /* remainder section */
}
while (true);

与test和的有界等待互斥set()

相同的数据结构是boolean wait [n]; 布尔锁 这些数据结构被初始化为false。为了证明满足互斥要求的观点,我们注意到过程P;仅当waiting [i] == false或key-false时,才能进入其关键部分。仅当TestAndSet()执行键时,键的值才能变为false 。第一个执行TestAndSet()will的过程将找到key == false; 其他所有人必须等待。仅当另一个进程离开其临界区时,变量waiting [i]才可能变为false。只有一个等待[i]设置为false,才能满足互斥要求。

为了证明满足进度要求这一点,我们注意到为相互排斥而提出的论点在这里也适用,因为退出关键部分的进程将锁设置为false或将waiting [j]设置为false。它们都允许等待进入其关键部分的过程继续进行。为了证明满足有界等待条件这一点,我们注意到,当进程离开其临界区时,它将以循环顺序(z'+ 1,i + 2,...,n- 1,0,...,i — 1)。它按此顺序将进入部分(等待[j] =-true)中的第一个过程指定为进入关键部分的下一个过程。

任何等待进入其临界区的过程都将在n-1圈内完成。不幸的是,对于硬件设计人员而言,TestAndSet()在多处理器上实现原子指令并不是一件容易的事。