Promela中的原子序列。文档中的矛盾

时间:2017-03-30 19:17:41

标签: formal-verification promela spin

这里,http://spinroot.com/spin/Man/Manual.html,写道:

  

在Promela中还有另一种避免测试和设置的方法   问题:原子序列。通过为一系列语句添加前缀   用大括号括起来,用户可以指示关键字atomic   该序列将作为一个不可分割的单位执行,   与任何其他进程不交错。 导致运行时错误   如果除第一个语句之外的任何语句都阻塞在原子语中   序列即可。这就是我们如何使用原子序列来保护原子序列   在前面的例子中并发访问全局变量状态。

在这里,http://spinroot.com/spin/Man/atomic.html,写道:

  

如果原子序列中的任何语句阻塞,原子性就会丢失   如果原子序列中的任何语句阻塞,原子性就会丢失,   然后允许其他进程开始执行语句。   当被阻止的语句再次变为可执行时,执行   原子序列可以随时恢复,但不一定   立即。在进程可以恢复原子执行之前   在序列的其余部分,该过程必须首先与所有人竞争   系统中的其他活动过程重新获得控制权,即它   必须首先安排执行。

那么,真实的是什么?从第一次引用中我们可以了解到它不允许在原子中阻塞(不是第一个语句)

从第二次引用中我们了解到可以在原子上阻止它。你只是失去了原子性,就是这样。

1 个答案:

答案 0 :(得分:0)

矛盾文档:

我的猜测是矛盾仅仅是文档部分内容未被更新以反映多年来在 Spin 中发生的变化的结果。

事实上,在{strong> Spin v的release notes中。 2.0 我们可以找到以下文本(重点是我的):

  

2.3.1阻止原子序列

     

到目前为止,如果包含原子序列,则认为是错误   任何可能阻止序列执行的陈述。这个   造成了很多混乱,并且不必要地使建模变得复杂。开始   使用Spin版本2,阻止原子序列是合法的。如果一个   在原子序列块内处理,控制转移   对另一个过程不确定。如果声明以后   变得可执行,控制可以返回进程和原子   继续执行序列的其余部分。

     

语义的这种变化使得模型相对容易   实例,控制不从一个进程传递到的协同例程   另一个,除非正在运行的进程阻止。

Promela的原子声明:

在当前版本的 Promela / Spin 中,存在两个原子序列

    来自atomic:
  • docs,重点是我的:

      

    <强>描述

         

    如果括号中包含一系列语句并以关键字atomic 作为前缀,则表示该序列将作为一个不可分割的单元执行,与其他进程不交错。在流程执行的交错中,从执行原子序列的第一个语句到最后一个语句完成之前,没有其他进程可以执行语句。序列可以包含任意Promela语句,并且可能是非确定性的。

         

    如果原子序列中的任何语句阻塞,原子性丢失,然后允许其他进程开始执行语句。当被阻止的语句再次变为可执行时,原子序列的执行可以是随时恢复,但不一定立即恢复。在进程可以恢复序列其余部分的原子执行之前,进程必须首先与系统中的所有其他活动进程竞争以重新获得控制权,即必须首先将其安排执行。

         

    [...]

  • 来自d_step:
  • docs,重点是我的:

      

    说明

         

    执行 d_step 序列,好像它是一个不可分割的语句。它与原子序列相当,但它在以下三点上与这些序列不同:

         
        
    • 不允许goto跳入或跳出d_step序列。
    •   
    • 确定性地执行序列。如果存在非确定性,则以固定和确定的方式解决,例如,始终在每个选择和重复结构中选择第一个真正的保护。
    •   
    • 如果序列中任何语句的执行都可以阻止,则会出错。这意味着,例如,在大多数情况下,发送和接收语句不能在d_step序列中使用。
    •   
         

    [...]

当然,实际上可以使用简单的 Promela示例来测试此行为。

测试1:使用atomic {}

失去原子性

采用以下 Promela模型,其中两个进程pippopluto执行atomic {}指令序列,最多10次。每个进程在开始执行原子序列时将其唯一_pid保存在全局变量p内,然后检查flag变量:

  • 如果flagtruepippo可以执行但pluto不能执行,因此pluto应该暂时失去原子性(在某些执行跟踪中)
  • 如果flagfalsepluto可以执行但pippo不能执行,因此pippo应该暂时失去原子性(在某些执行跟踪中)

我们通过在assert(p == _pid)中的原子序列末尾添加pippo指令来检查最新案例。如果条件未被违反,则意味着没有执行pippo从原子序列中失去原子性而pluto开始执行。否则,我们证明atomic {} bool flag; pid p; active proctype pippo () { byte i; do :: i < 10 -> atomic { true -> p = _pid; flag; /* executable only if flag is true */ printf("pippo unblocked\n"); flag = !flag; assert(p == _pid); }; i++; :: else -> break; od; }; active proctype pluto () { byte i; do :: i < 10 -> atomic { true -> p = _pid; end: !flag; /* executable only if flag is false */ printf("pluto unblocked\n"); flag = !flag; }; i++; :: else -> break; od; }; 中的描述准确无误。

~$ spin -search -bfs test.pml    # -bfs: breadth-first-search, results in a 
                                 # shorter counter-example

pan:1: assertion violated (p==_pid) (at depth 6)
pan: wrote test.pml.trail

(Spin Version 6.4.3 -- 16 December 2014)
Warning: Search not completed
    + Breadth-First Search
    + Partial Order Reduction

Full statespace search for:
    never claim             - (none specified)
    assertion violations    +
    cycle checks            - (disabled by -DSAFETY)
    invalid end states      +

State-vector 20 byte, depth reached 6, errors: 1
       15 states, stored
          10 nominal states (stored-atomic)
        0 states, matched
       15 transitions (= stored+matched)
        5 atomic steps
hash conflicts:         0 (resolved)

Stats on memory usage (in Megabytes):
    0.001   equivalent memory usage for states (stored*(State-vector + overhead))
    0.290   actual memory usage for states
  128.000   memory used for hash table (-w24)
  128.195   total actual memory usage

pan: elapsed time 0 seconds

如果我们使用 Spin 执行形式验证,它会发现违反该属性的执行跟踪:

 ~$ spin -t -p -l -g test.pml

违反断言,如文档中所述。您可以按如下方式重播无效的执行跟踪:

flag:

仔细检查。现在,如果您对pippo内的说明pippo发表评论并重复验证过程,那么您会看到赢得了#{1}} t是违反断言的任何执行跟踪。 这是因为d_step {}的原子序列中没有其他指令可以阻止,因此原子性永远不会丢失。

TEST 2:使用atomic

阻止错误

现在,使用相同的代码示例,将pippo内的d_step关键字替换为bool flag; pid p; active proctype pippo () { byte i; do :: i < 10 -> d_step { true -> p = _pid; flag; /* executable only if flag is true */ printf("pippo unblocked\n"); flag = !flag; assert(p == _pid); }; i++; :: else -> break; od; }; active proctype pluto () { byte i; do :: i < 10 -> atomic { true -> p = _pid; end: !flag; /* executable only if flag is false */ printf("pluto unblocked\n"); flag = !flag; }; i++; :: else -> break; od; };

~$ spin -search -bfs test.pml 
pan:1: block in d_step seq (at depth 2)
pan: wrote test.pml.trail

(Spin Version 6.4.3 -- 16 December 2014)
Warning: Search not completed
    + Breadth-First Search
    + Partial Order Reduction

Full statespace search for:
    never claim             - (none specified)
    assertion violations    +
    cycle checks            - (disabled by -DSAFETY)
    invalid end states      +

State-vector 20 byte, depth reached 2, errors: 1
        4 states, stored
           4 nominal states (stored-atomic)
        0 states, matched
        4 transitions (= stored+matched)
        0 atomic steps
hash conflicts:         0 (resolved)

Stats on memory usage (in Megabytes):
    0.000   equivalent memory usage for states (stored*(State-vector + overhead))
    0.290   actual memory usage for states
  128.000   memory used for hash table (-w24)
  128.195   total actual memory usage

pan: elapsed time 0 seconds

如果您正式验证此模型,您会发现它仍然找到了一个反例,但这次出现了不同的错误:

~$ spin -t -p -l -g test.pml
using statement merging
  1:    proc  1 (pluto:1) test.pml:26 (state 1) [((i<10))]
  2:    proc  0 (pippo:1) test.pml:8 (state 1)  [((i<10))]
  3:    proc  0 (pippo:1) test.pml:9 (state 8)  [(1)]
  3:    proc  0 (pippo:1) test.pml:11 (state 3) [p = _pid]
spin: trail ends after 3 steps
#processes: 2
        flag = 0
        p = 0
  3:    proc  1 (pluto:1) test.pml:27 (state 7)
  3:    proc  0 (pippo:1) 
2 processes created

对应于以下执行跟踪:

pippo

问题是d_step序列中的d_step阻塞,这违反了{{1}的概要中的第三个​​条件 } linked documentation,完全如上所述。

仔细检查。同样,如果您对flag;说明发表评论,您会发现不会有任何错误跟踪。