【问题标题】:Trying to understand the Peterson's N-Process Algorithm试图理解彼得森的 N 过程算法
【发布时间】:2014-11-02 17:02:18
【问题描述】:

我正在尝试理解 Peterson 的 N 过程算法,但遇到了这个问题。

问题:假设 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;

假设系统在任何给定时间的状态由&lt;flags[0], flags[1], flags[2], turn[0], turn[1]&gt; 值和当前执行进程的 id 定义。进一步假设系统的当前状态是&lt;0,0,0,2,-1&gt;,进程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,但是它将如何帮助我们从哪里开始跟踪代码呢?

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

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

为什么给我们状态值以及它如何帮助我们找到从哪里开始跟踪代码。

如果我能得到一些提示来帮助我开始追踪代码,那就太好了。

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

【问题讨论】:

    标签: c algorithm concurrency process


    【解决方案1】:

    由于您没有要求问题的答案,并且您提出了一个合理且明智的问题,我相信我可以为您指明正确的方向,而无需直接为您完成作业(或其他任何事情)。

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

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

    由此我们可以假设系统正常启动并在执行期间到达该状态。所以我们需要找到系统可以处于该状态并且进程0正在执行的点。下一部分给了我们一些回旋余地:

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

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

    此外,我们可以看到所有进程都运行一次并退出 - 存在一个循环,但我们还可以看到它在每一轮增加 flags 的值,因此我们可以很好地猜测我们只为变量值打一次这个场景。但我们应该通过它来找出答案。

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

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

    我认为您的措辞很糟糕,我怀疑您了解现实情况是每个进程都从头开始并运行到结束,因此“当一个进程在 CPU 上执行时,它会从它停止的地方开始并可能运行任何数量的指令,直到它失去在 CPU 上运行的权利(指令的数量取决于控制系统的任何东西)”是更准确的说法。

    所以最简单的方法就是从头开始转动手柄。问题没有这么说,但标志和转弯通常初始化为-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 所以

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

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

    您还可以看到,如果进程 2 在其他人有机会之前立即执行了所有行,然后是进程 1,然后是进程 0,那么您最终会在同一个地方结束。如果您以各种方式处理整个系统,您会发现模式相似(请注意,无法保证进程执行其关键部分的顺序,这取决于谁在有争议的线路上“获胜”)。

    所以回到最初的问题,只有少数几个地方进程 0 可以控制该系统状态。在wait 行上,或者在计数增加到 1 时的for 行上(在循环循环之后)或在它设置flag[0] 的行上。之后系统状态就不一样了。最好假设最早的进程 1 没有被阻塞(还)并且也可以改变状态。

    为了完整起见,最后一道皱纹。还有一个地方可以控制该过程,并且系统状态可以是这样的。它就在turn[count] = i; 行之前。在这种情况下,进程 2 刚刚设置了变量,进程 0 即将覆盖它。您可以从这里继续,但它将是循环的过程 1 和 2。我包括这个预期的评论,我实际上并不是建议你以此为起点,尽管它是完全有效的。几乎可以肯定,这个问题希望您从进程 0 和 1 开始循环,而 2 在繁忙的等待中被阻塞,以查看从那里发生的情况。

    祝你好运。

    【讨论】:

      猜你喜欢
      • 2014-12-28
      • 1970-01-01
      • 1970-01-01
      • 2012-07-20
      • 2013-02-17
      • 2011-02-24
      • 2017-05-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多