你说得对,孩子们
应该免于饥饿,事实上,的确如此。
饥饿
当进程
请求一些资源
但确实如此
一直拒绝他们
. 因此,更好地编码
进步
公式为:
ltl p1 { [] (P[0]@req -> <> (P[0]@cs) }
req
标签的位置如下:
do
:: true ->
req: want[me] = true
turn = you
!want[you] || turn == me
cs: want[me] = false
od
false
原因是
进程调度器
你是系统的一员
模型检查
一般来说,
. 事实上,它承认在执行过程中
_pid
等于
0
永远不会选择执行。
这个
spin
model checker为您提供了一个正好属于这种情况的反例:
~$ spin -t -g -l -p t.pml
ltl ltl_0: [] (<> ((P[0]@cs)))
starting claim 1
using statement merging
Never claim moves to line 3 [(!((P[0]._p==cs)))]
2: proc 1 (P:1) t.pml:10 (state 1) [want[me] = 1]
want[0] = 0
want[1] = 1
<<<<<START OF CYCLE>>>>>
Never claim moves to line 8 [(!((P[0]._p==cs)))]
4: proc 1 (P:1) t.pml:11 (state 2) [turn = you]
6: proc 1 (P:1) t.pml:12 (state 3) [((!(want[you])||(turn==me)))]
8: proc 1 (P:1) t.pml:13 (state 4) [want[me] = 0]
want[0] = 0
want[1] = 0
10: proc 1 (P:1) t.pml:10 (state 1) [want[me] = 1]
want[0] = 0
want[1] = 1
spin: trail ends after 10 steps
#processes: 2
want[0] = 0
want[1] = 1
turn = 0
cs = 0
10: proc 1 (P:1) t.pml:11 (state 2)
10: proc 0 (P:1) t.pml:9 (state 5)
10: proc - (ltl_0:1) _spin_nvr.tmp:7 (state 10)
2 processes created
这个问题基本上有两种解决方法:
-
第一个问题是,如果
临界截面
一些过程
最终进入:
ltl p2 { [] ((P[0]@req || P[1]@req) -> <> (P[0]@cs || P[1]@cs) }
这确保了整个系统的进步,但并不能保证其中任何一个系统
P[0]
P[1]
特别是在
.
-
第二是引入
其中请求仅将模型检查的重点放在那些执行上,在这些执行中,进程被无限频繁地调度为执行:
ltl p3 { ([]<> (_last == 0)) -> [] (P[0]@req -> <> (P[0]@cs)) }
_last
是预定义的内部变量,如中所述
docs
具体如下:
当前执行序列中的步骤。初始值
是
这个
变量只能在never声明中使用。它是一个
在任何上下文中为此变量赋值时出错。
不挨饿
在你的模型上。这是因为
[] <> _last == 0
P[0]
由于调度器的不公平性,常常不能无限地调度执行,而且在那些情况下
P[0]
由于实际的问题而没有安排
.
一个合适的解决方案。
我建议你换个型号
执行
忙着等待
而不是
等待轮到自己时阻挡
_最后
当试图证明没有
饥饿
. 最终模型为:
bool flag[2], turn
active [2] proctype P() {
pid i = _pid;
pid j = 1 - i;
do
:: true ->
req: flag[i] = true
turn = j;
do
:: (flag[j] && (turn == j)) -> skip
:: else -> break;
od;
cs: skip;
flag[i] = false;
od
}
ltl p1 { (
([]<> (_last == 0)) &&
([]<> (_last == 1))
) ->
([] (P[0]@req -> <> (P[0]@cs)))
}
属性确实得到了验证,而没有丢弃任何可能感兴趣的执行跟踪:
~$ spin -a t.pml
ltl p1: (! (([] (<> ((_last==0)))) && ([] (<> ((_last==1)))))) || ([] ((! ((P[0]@req))) || (<> ((P[0]@cs)))))
~$ gcc pan.c
~$ ./a.out -a
(Spin Version 6.4.8 -- 2 March 2018)
Full statespace search for:
never claim + (p1)
assertion violations + (if within scope of claim)
acceptance cycles + (fairness disabled)
invalid end states - (disabled by never claim)
State-vector 40 byte, depth reached 97, errors: 0
269 states, stored (415 visited)
670 states, matched
1085 transitions (= visited+matched)
0 atomic steps
hash conflicts: 0 (resolved)
Stats on memory usage (in Megabytes):
0.017 equivalent memory usage for states (stored*(State-vector + overhead))
0.287 actual memory usage for states
128.000 memory used for hash table (-w24)
0.534 memory used for DFS stack (-m10000)
128.730 total actual memory usage
unreached in proctype P
t.pml:18, state 16, "-end-"
(1 of 16 states)
unreached in claim p1
_spin_nvr.tmp:23, state 33, "-end-"
(1 of 33 states)
pan: elapsed time 0 seconds
请注意,我们需要两者
P[0]
和
P[1]
被允许无限频繁地执行,否则会发现另一个虚假的反例。
彼得森算法的这个模型不正确吗?