【SPIN】PROMELA远程引用与控制流验证(SPIN学习系列--5)
PROMELA语言提供了两种强大的机制用于验证并发系统:远程引用(remote references)和进程变量引用。这些机制使得在不引入额外状态变量的情况下,能够精确描述系统状态和属性。
远程引用(Remote References)
远程引用允许你直接引用进程中的控制位置(label),语法格式为:进程名@标签名
。这种引用返回一个布尔值,表示该进程是否处于指定的控制位置。
在临界区问题中,可以这样使用远程引用:
active proctype P() {do:: wantP = true; // 表达进入临界区的意愿!wantQ; // 检查Q是否不在临界区cs: wantP = false; // 临界区开始的标签od
}active proctype Q() {do:: wantQ = true; // 表达进入临界区的意愿!wantP; // 检查P是否不在临界区cs: wantQ = false; // 临界区开始的标签od
}// 使用远程引用定义互斥条件
#define mutex !(P@cs && Q@cs)// 验证互斥性:在所有状态下mutex都必须成立
never { []mutex }
关键知识点:
- 标签(cs)标记了临界区的入口点
P@cs
和Q@cs
分别表示进程P和Q是否处于临界区mutex
宏定义了互斥条件:P和Q不能同时处于临界区- never claim中的
[]mutex
表示"永远满足mutex条件"
进程变量引用
PROMELA还允许引用其他进程的局部变量,语法格式为:进程名:变量名
。这在验证算法正确性时非常有用。
例如,我们可以直接检查另一个进程的标志变量:
active proctype P() {byte turn;do:: turn = 1; // 设置自己的优先级!Q:turn; // 检查Q是否没有优先级cs: /* 临界区 */od
}active proctype Q() {byte turn;do:: turn = 1; // 设置自己的优先级!P:turn; // 检查P是否没有优先级cs: /* 临界区 */od
}
关键知识点:
P:turn
和Q:turn
分别引用进程P和Q的局部变量turn- 通过这种方式可以直接访问其他进程的状态
- 结合远程引用,可以构建更复杂的验证条件
验证过程与LTL
Spin模型检查器使用线性时态逻辑(LTL)来表达和验证系统属性。上面的例子中,[]mutex
是一个LTL公式,表示"mutex永远成立"。
其他常用的LTL操作符包括:
<>property
:表示"最终会满足property"[]<>property
:表示"无限多次满足property"property1 U property2
:表示"property1一直成立直到property2成立"
完整示例代码
下面是一个完整的使用远程引用和变量引用的PROMELA模型:
bool wantP = false;
bool wantQ = false;active proctype P() {do:: wantP = true; // 表达进入临界区的意愿!wantQ; // 检查Q是否不在临界区cs: wantP = false; // 临界区开始的标签/* 临界区代码 */wantP = true; // 离开临界区od
}active proctype Q() {do:: wantQ = true; // 表达进入临界区的意愿!wantP; // 检查P是否不在临界区cs: wantQ = false; // 临界区开始的标签/* 临界区代码 */wantQ = true; // 离开临界区od
}// 定义互斥条件
#define mutex !(P@cs && Q@cs)// 定义无饥饿条件
#define no_starvation (<>P@cs || <>Q@cs)// 验证互斥性
never { []mutex }// 验证无饥饿性
ltl starvation_free { [] (P:wantP -> <> P@cs) && [] (Q:wantQ -> <> Q@cs) }
通过这些机制,PROMELA能够精确表达和验证并发系统的各种属性,为系统设计提供强有力的保障。
要验证上面提供的PROMELA模型,需要使用SPIN模型检查器执行一系列命令。以下是完整的验证流程及对应的命令行操作:
1. 编译PROMELA模型生成验证程序
spin -a model.pml
-a
选项指示SPIN生成验证所需的ANSI C代码model.pml
是你的PROMELA模型文件名
2. 编译验证程序
gcc -o pan pan.c
pan.c
是SPIN生成的C代码文件-o pan
指定输出可执行文件名为pan
3. 验证互斥性属性
./pan -a -n
-a
选项记录所有错误路径-n
选项验证never claim(即互斥性属性[]mutex
)
4. 验证无饥饿性LTL属性
./pan -a -l -f "[] (P:wantP -> <> P@cs) && [] (Q:wantQ -> <> Q@cs)"
-l
选项启用LTL属性验证-f
后跟具体的LTL公式进行验证
5. 验证无死锁
./pan -a -e
-e
选项检查系统是否存在死锁状态
6. 查看验证结果
如果验证过程中发现错误,SPIN会生成一个错误路径。使用以下命令查看详细错误信息:
spin -t -p -g model.pml
-t
选项进入跟踪模式-p
显示错误路径-g
生成图形化的错误路径
7. 优化验证过程
为提高验证效率,可以添加以下选项:
spin -DBITSTATE model.pml # 使用位状态哈希减少内存消耗
spin -DNFAIR=2 model.pml # 指定弱公平性条件
完整验证脚本示例
# 编译模型
spin -a model.pml# 编译验证程序(启用优化)
gcc -O2 -DREACH -o pan pan.c# 验证互斥性
./pan -a -n
if [ $? -eq 0 ]; thenecho "互斥性验证通过"
elseecho "互斥性验证失败,生成错误跟踪..."spin -t -p model.pml > mutex_error.txt
fi# 验证无饥饿性
./pan -a -l -f "[] (P:wantP -> <> P@cs) && [] (Q:wantQ -> <> Q@cs)"
if [ $? -eq 0 ]; thenecho "无饥饿性验证通过"
elseecho "无饥饿性验证失败,生成错误跟踪..."spin -t -p model.pml > starvation_error.txt
fi# 验证无死锁
./pan -a -e
if [ $? -eq 0 ]; thenecho "无死锁验证通过"
elseecho "发现死锁,生成错误跟踪..."spin -t -p model.pml > deadlock_error.txt
fi
这些命令将帮助你全面验证模型的正确性。如果发现错误,可以使用SPIN提供的详细错误信息来修改模型,直到所有属性都得到满足。