我正在尝试在promela中建模我的一个项目进行模型检查。在那,我在网络中没有N个节点。因此,对于每个节点,我正在制作一个流程。像这样:
init {
byte proc;
atomic {
proc = 0;
do
:: proc < N ->
run node (q[proc],proc);
proc++
:: proc >= N ->
break
od
}
}
所以,基本上,这里每个节点都是&#39;是一个将模拟我的网络中的每个节点的过程。现在,Node Process有3个线程在我原来的实现中并行运行,在这三个线程中我锁定了某个部分,这样三个线程就不会同时访问Critical Section。所以,对于promela中的这个,我做了类似的事情:
proctype node (chan inp;byte ppid)
{
run recv_A()
run send_B()
run do_C()
}
所以这里recv_A,send_B和do_C是网络中每个节点并行运行的三个线程。现在,问题是,如果我把锁放在recv_A,send_B,do_C使用原子,那么它将锁定所有3 * N进程,而我想锁定,以便锁定应用于三个组。也就是说,如果process1(运行recv_A的主节点进程)recv_A在其CS中,那么只有process1的send_B和do_C应该被禁止进入CS而不是进程2&#39; s recv_A,send_B,do_C。有没有办法做到这一点?
答案 0 :(得分:0)
您有多种选择,所有选项都围绕在N个进程中实现某种互斥算法:
Black&amp;白面包算法可用here。但请注意,这些算法 - 除了Peterson的算法之外 - 往往很复杂,可能会使您的系统验证变得不切实际。
一种简单的方法是采用 Test&amp; amp;设置算法,但仍然在尝试部分中使用atomic
。以下是从here获取的示例实现。
bool lock = false;
int counter = 0;
active [3] proctype mutex()
{
bool tmp = false;
trying:
do
:: atomic {
tmp = lock;
lock = true;
} ->
if
:: tmp;
:: else -> break;
fi;
od;
critical:
printf("Process %d entered critical section.\n", _pid);
counter++;
assert(counter == 1);
counter--;
exit:
lock = false;
printf("Process %d exited critical section.\n", _pid);
goto trying;
}
#define c0 (mutex[0]@critical)
#define c1 (mutex[1]@critical)
#define c2 (mutex[2]@critical)
#define t0 (mutex[0]@trying)
#define t1 (mutex[1]@trying)
#define t2 (mutex[2]@trying)
#define l0 (_last == 0)
#define l1 (_last == 1)
#define l2 (_last == 2)
#define f0 ([] <> l0)
#define f1 ([] <> l1)
#define f2 ([] <> l2)
ltl p1 { [] !(c0 && c1) && !(c0 && c2) && !(c1 && c2)}
ltl p2 { []((t0 || t1 || t2) -> <> (c0 || c1 || c2)) }
ltl p3 {
(f0 -> [](t0 -> <> c0))
&&
(f1 -> [](t1 -> <> c1))
&&
(f2 -> [](t2 -> <> c2))
};
在您的代码中,您应该为每组lock
个相关线程使用不同的3
变量。锁争用仍然会发生在全局级别,但在关键部分内部工作的某些进程不会导致其他进程等待属于同一线程组的进程。
另一个想法是利用频道来实现互斥:让每组线程共享一个共同的异步频道,该频道最初包含一个token
消息。只要其中一个线程想要访问临界区,它就会从通道中读取。如果token
不在频道内,则等待它变为可用。否则,它可以在关键部分继续前进,当它完成时,它会将token
放回共享频道。
proctype node (chan inp; byte ppid)
{
chan lock = [1] of { bool };
lock!true;
run recv_A(lock);
run send_B(lock);
run do_C(lock);
};
proctype recv_A(chan lock)
{
bool token;
do
:: true ->
// non-critical section code
// ...
// acquire lock
lock?token ->
// critical section
// ...
// release lock
lock!token
// non-critical section code
// ...
od;
};
...
这种方法可能最简单,所以我先选择这个。但请注意,我不知道在验证时间内如何影响性能,这很可能取决于Spin
内部处理通道的方式。可以在文件channel_mutex.pml
中找到此解决方案的完整代码示例here。
总而言之,请注意您可能希望将互斥,进度和锁定自由 LTL
属性添加到您的模型,以确保其行为正确。我们提供了这些属性定义的示例here,并提供了代码示例here。