如何在promela中实现重复直到(条件)循环?

时间:2017-10-05 08:41:19

标签: promela spin

这是正确的做法:

repeat{
...
} until(<condition>)
在普罗梅拉?

我试过了:

do::
 //..
(condition) -> break;
od

do ::
  //..
  if::(condition) -> break;
  else
  fi;
od

1 个答案:

答案 0 :(得分:2)

您的首次尝试不正确,因为如果<condition>不是true,则该过程将永远阻止。

您的第二次尝试在功能上是正确的。就个人而言,我更喜欢您的解决方案的一个小变体,它不会丢弃执行批量代码true条目。

鉴于

repeat{
    // bulk code
} until(<condition>)

您有以下选择:

  • do

    do
        :: true ->
            // bulk code
            if
                :: <condition> ->
                    break;
                :: else;
            fi;
    od;
    

    do
        :: true ->
            // bulk code
            if
                :: ! <condition>;
                :: else ->
                    break;
            fi;
    od;
    
  • goto

    L1:
        // bulk code
        if
            :: <condition>;
            :: else
                -> goto L1;
        fi;
    

    L1:
        // bulk code
        if
            :: ! <condition>
                -> goto L1;
            :: else;
        fi;
    
  • unless (不要使用!)

    do
        :: true ->
            d_step {
                // bulk code
            }
    od unless { <condition> };
    

    请注意,这种方法有两种方法:

    • 它假定<condition>的值在// bulk code内更改,而不是代码中的任何其他位置(,例如通过其他某个进程

    • 取决于// bulk code的内容,可能根本无法使用d_step

    仅在改变<condition>评估的指令正确 // bulk code内的最后一个的情况下,才允许一个删除d_step而不影响语义。

    要了解为何会出现这种情况,请在以下代码示例中观察Spin的行为:

    active proctype example()
    {
        int cc = 0;
        do
            :: true ->
                printf("before %d\n", cc);
                cc++;
                printf("after  %d\n", cc);
        od unless { cc == 3 };
    }
    

    具有以下输出:

    ~$ spin test.pml 
          before 0
          after  1
          before 1
          after  2
          before 2
    1 process created
    

    由于cc++改变了cc == 3的评估,但不是代码序列的最后一条指令,因此屏幕上永远不会打印语句after 3

修改

当然,我们也可以使用unless语句尝试另一种代码变体,例如

bool flag;
do
    :: true ->
        // bulk code
        flag = true;
        flag = false;
od unless { flag && <condition> };

这显然总是正确的,即使在一般情况下,但它会使用不属于原始问题的其他变量阻塞源代码,所以我仍然不鼓励使用unless来替换do/until

以下是如何使用它的示例:

active proctype example()
{
    int cc = 0;
    bool flag = false;
    do
        :: true ->
            printf("before %d\n", cc);
            cc++;
            printf("after  %d\n", cc);
            flag = true;
            flag = false;
    od unless { flag && (cc == 3) };
}

确实产生了正确的输出:

~$ spin test.pml 
      before 0
      after  1
      before 1
      after  2
      before 2
      after  3
1 process created