📜  N进程彼得森算法

📅  最后修改于: 2022-05-13 01:56:11.544000             🧑  作者: Mango

N进程彼得森算法

本主题的先决条件包括有关进程间同步以及如何获得同步的想法。此外,生产者-消费者问题的一些知识以及彼得森算法的思想是最重要的。

概述 :
任何操作系统中各种进程的执行之间的同步是最重要的。哪个进程将被允许执行他们可能正在更改某些重要变量的关键部分部分,此时在其他进程中了解非常重要,因为忽略它会导致不需要的结果或结果。因此,为了获得进程之间的同步,人们讨论和开发了许多技术,其中彼得森算法就是其中之一。生产者-消费者问题是最著名的临界区问题之一。在这种情况下,如果没有正确实现同步,则缓冲区内的项目计数将不断受到阻碍,并会导致不想要的结果。

描述 :
Peterson 的解决方案是一种基于软件的解决方案,用于解决竞争条件或临界区问题。它通常不会在现代计算机中实现,但该解决方案提供了解决临界区问题的基本算法方法。我们将在本文中主要考虑生产者-消费者问题。起初,这个算法很容易提出,目的是在两个进程之间建立同步。所以可以进一步扩展,通过对它做一个小的改动来考虑 N 个进程之间的同步。

Peterson 对 2 个进程的解决方案:
让我们考虑在操作系统中并行工作的 2 个进程。这些进程正在修改相同的变量,因此它们都有进入竞争条件的风险。我们认为每个进程都有一个剩余部分,它们不会修改这些可能导致竞争条件的变量,另一个部分称为临界区,其中进程可能有机会进入竞争条件。因此,下面给出了用于此类情况的基本彼得森算法。

第1步 :
让我们考虑名为 P 0和 P 1的两个进程。所以我们可以使用一个简单的公式在这两个过程之间切换,即 1-<过程基数>。要将指针从 P 1更改为 P 0 ,应通过公式将其更改为 idx = 1-1 (P 1 的基数) = 0。因此,这样 idx 在任何时候都将指向 P 1或 P 0 .



第2步 :
该算法需要在进程之间共享两个数据项。

int turn;

该变量指示轮到谁来执行其程序的临界区部分。如果turn == 1,则轮到P 1进入临界区。

boolean flag[2];

此数组指示进程是否准备好进入其临界区。 flag[0]==true 表示 P 0已准备好执行其程序的临界区部分。

第 3 步:
下面给出该算法的主要部分。该过程如果要进入程序的临界区部分,则必须执行以下两件事。

  1. 设置标志[idx] = true。如果 P 1想要进入比它应该设置 flag[1]=true。
  2. 设置turn = 1-idx,即如果P 1想要进入,那么它应该根据另一个进程设置turn,因为这意味着如果另一个进程希望进入临界区部分,则可以在P 1执行其部分之后这样做。

第四步 :
该算法如下所示。在以下两种情况发生之前,任何进程都被禁止进入程序的临界区。

1) if flag[1-idx]==true
2) if turn == 1-idx.

现在,直到上述两个条件都为真,进程在 while 循环中等待什么都不做,如果任何一个条件变为非真,进程进入临界区,下一个进程(即 1-idx)正在循环中等待执行如果需要,关键部分部分。这也保证了不会有两个进程同时执行临界区部分。

伪代码 –
因此,算法的伪代码可以给出如下。

idx=0;

do{    

// preparing to enter the critical section part
flag[idx] = TRUE;
turn = 1-idx;

while(flag[1-idx]==TRUE and turn == 1-idx)        
// checking the two variables continuously. This is a waste of time.
;   
// continues in the loop till chance cames

/*
Critical section part
*/

flag[idx] = FALSE;

/*
Remainder section part
*/
}

因此,通过这种方式,两个进程之间存在同步。上述算法保证了两个进程之间始终存在互斥和同步。



N-Process 的 Peterson 算法:
该算法采用与上面讨论的相同的数据结构。它唯一的修改是它使用了一个 N 大小的数组,并且变量 turn 可以具有从 0 到 N-1 的值。这个算法也有很大的变化,因为在上面的算法中,在 while 条件下,我们不断地引用转弯变量来包含互补过程的编号。但在这个算法中,情况并非如此,因为有超过 2 个进程。

执行 -
下面给出实现上述算法的思路。

第1步 :
让我们考虑一个大小为 N 的队列,其中要放置 N 个进程。现在假设我们编写了一个算法,每个进程在某个时间将自己推入队列以到达队列的末尾,然后他们将被允许执行其临界区并离开队列。通过这种方式,我们可以保证每个进程一旦进入队列并到达其末尾(前端)就可以执行其临界区。在进程到达前端之前,它必须等待,因为此时可能会发生两种情况。

  • 某些进程可能位于队列中的下一个索引处并正在等待其他进程。
  • 或者如果任何后台进程(进入队列较晚)没有移动到当前进程的位置。 (这意味着后端进程检查前端是否已清空并希望将队列向前推。)

第一种情况很清楚,但在第二种情况下有一个技巧(或者我们可以说是一个想法)。看完第二点你就明白了。

第2步 :
该算法的数据结构与2个进程一个相同,但现在Turn变成了一个大小为N的数组,而Flag也是一个大小为N的数组。

Flag[PID] 
// has size N  and PID always ranges from 0---N-1 since there are N processes.

以指示该PID过程是在队列中的位置。

Turn[i] = PID // has size N
  • 标记到目前为止没有进程说它在位置 i (因为如果有任何进程这样说,那么这意味着有来自后面进程的后推,因此当前进程应该改变它的位置)。
  • Back-Push 的发生是因为一些进入队列较晚的进程应该被给予进入的地方,因此存在一个推送到队列前面的休息进程。由于系统在多处理器环境中工作,并发执行进程,因此出现了反推。
  • 此外,队列的大小可能会慢慢减小,因为某些进程在执行其临界区后可能会终止或离开队列或进入另一个临界区。

因此,下面解释了 N 进程 Peterson 算法的伪代码。

  • 我们将创建两个名为 lock() 和 unlock() 的函数。在 lock()函数,进程一直等到它到达队列的末尾,而在 unlock()函数,它标志着从队列中退出。
  • 临界区的执行发生在进程处于队列末尾时,即在锁定和解锁方法之间。
  • 下面分别介绍这两种方法。
LOCK( Process PID){
    for( int i = 0;i

因此,下面给出了上述算法的伪代码。

LOCK( Process PID){
    for( int i = 0;i

结论 :
可以清楚地看到,上述算法遵守了任何多处理器环境中同步和并发进程要满足的所有规则。因此,我们能够了解 Peterson 算法如何适用于 N 进程。