试图了解彼得森的N过程算法

时间:2014-11-02 17:02:19

标签: c algorithm concurrency process

我想了解彼得森的N-Process算法,我遇到了这个问题。

问题: 假设有3个进程拥有进程ID 0, 1 and 2。这些进程在单处理器上并发执行,并使用Peterson的N进程算法来控制临界区的执行。每个进程都运行以下伪代码:

lock(pid);
<critical section>;
unlock(pid

其中lock()unlock()函数定义为

lock(for Process i):

/* repeat for all partners */
for (count = 0; count < (NUMPROCS-1); count++) {
    flags[i] = count;
    turn[count] = i;
    "wait until (for all k != i, flags[k]<count) or (turn[count] != i)"
}


Unlock (for Process i):

/* tell everyone we are finished */
flags[i] = -1;

假设在任何给定时间系统的状态由<flags[0], flags[1], flags[2], turn[0], turn[1]>值和当前正在执行的进程的id定义。进一步假设系统的当前状态为<0,0,0,2,-1>,其中进程0 当前正在执行 。从这个状态开始,显示三个进程从一个特定的方式运行到完成。当您跟踪三个进程的并发执行时,请在每一步显示系统的状态。

我的观察

在单处理器上并发运行的进程无法同时在CPU上执行。其中只有一个可以一次在CPU上执行。 当一个进程在CPU上执行时,它可以执行其代码的任何部分。

// NUMPROCS = 3

- 适用于i = 0

lock(for Process 0):
for (count = 0; count < 2; count++) {
    flags[0] = count;
    turn[count] = 0;
    "wait until (for all k != 0, flags[k]<count) or (turn[count] != 0)"
}


Unlock (for Process 0):
flags[0] = -1;

- 适用于i = 1

lock(for Process 1):
for (count = 0; count < 2; count++) {
    flags[1] = count;
    turn[count] = 1;
    "wait until (for all k != 1, flags[k]<count) or (turn[count] != 1)"
}


Unlock (for Process 1):
flags[1] = -1;

- 适用于i = 2

lock(for Process 2):
for (count = 0; count < 2; count++) {
    flags[2] = count;
    turn[count] = 2;
    "wait until (for all k != 2, flags[k]<count) or (turn[count] != 2)"
}


Unlock (for Process 2):
flags[2] = -1;

我的问题是 从哪里开始跟踪代码?给出了flags[0]=0, flags[1]=0, flags[2]=0, turn[0]=2, turn[1]=-1,但它是如何帮助我们开始跟踪代码的?

  • 如果我们从流程0 for循环之前开始,那么所有 转弯值将被设置为除给定值之外的不同值 给我们。

  • 如果我们假设通过执行问题意味着进程0就在其中 关键部分然后下一个进程的for循环将设置 将值转换为其他值。

为什么给他们我们状态值以及它如何帮助我们找到开始跟踪代码的位置。

如果我得到一些提示来帮助我开始跟踪代码,那将会很棒。

谢谢你,抱歉这个长期的问题。

1 个答案:

答案 0 :(得分:7)

既然你没有问这个问题的答案,并且你问了一个合理而明智的问题,我相信我可以指出你正确的方向,而不会直接为你完成你的作业(或其他)。

首先,问题的关键部分在于:

  

假设在任何给定时间系统的状态由<flags[0], flags[1], flags[2], turn[0], turn[1]>值和当前正在执行的进程的id定义。进一步假设系统的当前状态为<0,0,0,2,-1>,进程0 当前正在执行

由此我们可以假设系统正常启动并在执行期间到达该状态。因此,我们需要找到系统处于该状态并且进程0正在执行的点。下一部分为我们提供了一些摆动的空间:

  

显示从此状态开始的三个进程运行完成的一种特定方式。

因此,可能有多种方法可以在执行进程0的情况下获取这些变量值,但是可以找到任何一个并从那里开始完成系统。

此外,我们可以看到所有进程都运行一次并退出 - 有一个循环,但我们也可以看到它在每个回合中增加flags的值,所以我们可以很好地猜测我们只对变量值进行一次这种情况。但我们应该通过它来找出答案。

进程同时运行,但在单个处理器上运行。因此实际上只有一个执行但是一些更高的功率(例如操作系统)以我们无法确定的方式在它们之间切换。你说:

  

当一个进程在CPU上执行时,它可以执行其代码的任何部分。

我认为你只是措辞严重,我怀疑你明白现实是每个进程从一开始就一直运行直到它结束,因此&#34;当一个进程在CPU上执行时它启动它停止运行的地方可以运行任意数量的指令,直到它失去在CPU上运行的权利(指令的数量取决于控制系统的任何指令)&#34;是一个更准确的陈述。

所以最简单的方法就是从头开始并转动手柄。问题并没有说明,但标志和转弯通常会初始化为-1,所以一开始我们就有:

flags = [ -1, -1, -1 ]; turn = [ -1, -1 ] 

由于事情同时运行,让我们假设每个进程有效地同时执行每一行。它没有任何区别,因为你希望以后可以自己看到。

for (count = 0; count < (NUMPROCS-1); count++) {

好的,所有进程的count = 0,它们都进入下一行:

flags[i] = count;

现在:

flags = [ 0, 0, 0 ]; turn = [ -1, -1 ]

到目前为止,这么好 - 下一行:

turn[count] = i;

好的,这有问题 - 每个进程都会尝试设置相同的变量。其中一个会赢,但我们不知道哪一个:

flags = [ 0, 0, 0 ]; turn = [ ?, -1 ]

除了我们这样做之外,问题就在于此。我们可以turn[0] = 2。所以我们处于一个合适的变量状态,我们可以假设过程0处于控制之中,我们知道它在这一行:

"wait until (for all k != i, flags[k]<count) or (turn[count] != i)"

为了让你开始,对于进程0,count = 0和i = 0 so

"wait until (for all k in {1,2}, flags[k]<0) or (turn[0] != i)"

您可以看到or子句为false,因此进程0将再次绕过循环。因此,处理1. for all k条款对任何人都不适用。因此,进程2将因turn[0]的值而等待 - 您也可以看到它永远不会改变,因此进程2现在被锁定,等待for all k子句变为真 - 事实上& #39;这个系统如何运作的关键。如果您按照逻辑来回答问题,您将看到进程如何相互锁定,以便只有一个进程一次执行临界区。只要继续做我上面所做的事情,因为你只需要找到一条可以同时执行线路的路径,当有潜在的冲突时,只需选择一个值并从那里开始。

您还可以看到,如果流程2在其他人有机会之前立即执行了所有行,然后处理1然后处理0,您最终会在同一个地方。如果您以各种方式处理整个系统,您会发现类似的模式(请注意,流程执行其关键部分的顺序并不能保证,这取决于谁赢了&#39; ;在有争议的线上)。

回到最初的问题,只有少数地方可以使用该系统状态控制进程0。可以在wait行,也可以在for行,当计数增加到1(循环后)或者设置flag[0]的行。之后,系统状态不一样。最好假设最早的一个,因为过程1没有被阻止(还),也可能改变状态。

最后一个皱纹,完整性。还有另一个地方可以控制该流程,系统状态可以是这样的。它就在turn[count] = i;行之前。在这种情况下,进程2刚刚设置了变量,进程0即将覆盖它。你可以从这里继续,但它将是围绕循环的进程1和2。我包括这个期待有关它的评论,我并没有真正建议你使用它作为起点虽然它完全有效。这个问题几乎肯定会让你从循环中的进程0和1开始,在繁忙的等待中阻塞2,看看从那里发生了什么。

祝你好运。