我正在编写一个简单的客户端-服务器交互规范来学习 TLA+:
-------------------------------- MODULE Bar --------------------------------
VARIABLES
sessionOK, \* if session is OK or expired
msg \* message currently on the wire
vars == <<msg, sessionOK>>
TypeOK ==
/\ sessionOK \in {TRUE, FALSE}
/\ msg \in {
"Query",
"OK",
"Unauthorized",
"null"
}
Init ==
/\ msg = "null"
/\ sessionOK = FALSE
Query ==
/\ msg \in {"null", "OK"}
/\ msg' = "Query"
/\ UNCHANGED <<sessionOK>>
OK ==
/\ msg = "Query"
/\ sessionOK = TRUE
/\ msg' = "OK"
/\ UNCHANGED <<sessionOK>>
Unauthorized ==
/\ msg = "Query"
/\ sessionOK = FALSE
/\ msg' = "Unauthorized"
/\ UNCHANGED <<sessionOK>>
Authorize ==
/\ msg = "Unauthorized"
/\ msg' = "null"
/\ sessionOK' = TRUE
Expire ==
/\ sessionOK = TRUE
/\ sessionOK' = FALSE
/\ UNCHANGED <<msg>>
Next ==
\/ Query
\/ Unauthorized
\/ OK
\/ Authorize
\/ Expire
Spec == Init /\ [][Next]_vars /\ WF_vars(Next)
=============================================================================
正如您所希望看到的,客户端可以对服务器运行一些查询,如果会话正常,它将得到一个结果,否则它会收到一条需要授权然后重试的消息。会话可以随时到期。
我想确保客户端最终会得到结果,所以我在属性中添加了这一行:
(msg = "Query") ~> (msg = "OK")
在模型检查时,我遇到了一个这样的反例:Init -> (Query -> Unauthorized -> Authorize -> Expire),括号中的部分无限重复。我的第一个想法是对OK
step 提出强烈的公平要求。然而,问题是在这种情况下,OK
步骤从未启用。
我可以添加诸如[]<><<OK>>_vars
(其内容为“最终OK
发生的情况总是如此”)之类的内容,但这感觉像是在作弊,并且从我收集到的内容中,使用任意时间公式指定活跃度——而不是弱公平或强公平——是不受欢迎的。
如何使用弱公平或强公平来保证查询最终会得到响应?还是我的模型不好?我没主意了...