通过例子学TLA+(五)--FIFO & Sequences

FIFO

本例子是一个先进先出FIFO的Buffer。Sender向Buff发送数据,Buffer接收数据存储在Sequence中,然后,Buffer将Sequence中第一个数据取出发送给Receiver。可以理解为上一例子的复杂应用。
在这里插入图片描述
TLA+提供了 Sequences module可以直接使用,该module提供了 Append,Tail,Head,Len 等常见接口。

\* module使用之前要先Extend
EXTENDS Sequences

\* 初始化一个seq
VARIABLE q
q = <<>>  \* q为空sequence

Seq(S) \* 集合S中所有元素序列的集合,例如<<3,7>>是Seq(<<3,7,9>>)的一个元素
Head(s) \* 取sequence s中的第一个元素,例如Head(<<3,7>>)等于3
Tail(s)  \* 取sequence s中的最后一个元素,例如Tail(<<3,7>>)等于7
Append(s,e) \* 将元素e添加到sequence s的最后,例如Append(<<3,7>>,9) 等于 <<3,7,9>>
s \o t    \* 连接两个sequence,例如<<3,7>> \o <<5,9>> 等于 <<3,7,5,9>>
Len(s) \* 返回sequence s的长度,例如 Len(<<3.7>>) 等于2

TLA+实现过程

本例子可以理解为上一例子Interface的复杂版本,在FIFO中,相当于,sender与buffer之间,buffer与receiver之间的两个interface。根据之前的例子可以看出,TLA+的实现过程通常分为以下几步:1、引入module,定义变量,2、定义变量合法范围,3、定义初始化状态,4、定义可操作动作,5、定义基于初始化状态的下一步动作

1、先导入需要打module,定义需要的变量

----------------------------- MODULE FIFO ------------------------------ 
EXTENDS Naturals,Sequences 
CONSTANT Message   \* 集合Message为Sender发送的数据范围
VARIABLE inval,inrdy,inack  \* sender发送的数据和发送标识
VARIABLE outval,outrdy,outack \* receiver接收的数据与接收标识
VARIABLE q  \* q为sequence

2、定义上述变量的合法范围

InChannelTypeInvariant == inval \in Message /\ inrdy \in {0,1} /\ inack \in {0,1}
OutChannelTypeInvariant == outval \in Message /\ outrdy \in {0,1} /\ outack \in {0,1}
\* q 的合法范围为集合Message的元素序列的集合
TypeInvariant == InChannelTypeInvariant /\ OutChannelTypeInvariant /\ q \in Seq(Message)

3、定义初始化状态

\* Sender 初始化状态如下
InChannelInit == InChannelTypeInvariant /\ inrdy = inack 

\* Receiver 初始化状态如下
OutChannelInit == OutChannelTypeInvariant /\ outrdy = outack 

\* Buff 初始化状态如下
BufInit == q = <<>> 

\* 整体状态初始化如下
Init == InChannelInit /\ OutChannelInit /\ BufInit 

4、定义可操作性动作

在Interface例子中,有Sender发送数据,Receiver接收数据两个动作,在本例子中,则会有以下动作:

\* sender发送数据给buff
CanInSend == inrdy = inack
Send(d) == CanInSend /\ inval' = d /\ inrdy' = 1 - inrdy /\ UNCHANGED <<inack,outval,outrdy,outack,q>>

\* buff接收数据
CanBufRev == inrdy # inack
BufRev == CanBufRev /\ q' = Append(q,inval) /\ inack' = 1- inack /\ UNCHANGED <<inval,inrdy,outval,outrdy,outack>> 

\* buff发送数据给receiver
CanBufSend == outrdy = outack
BufSend == CanBufSend /\ q # <<>> /\ outval' = Head(q) /\ q' = Tail(q) /\ outrdy' = 1 - outrdy /\ UNCHANGED <<inval,inrdy,inack,outack>> 

\* eceiver接收数据
CanOutRev == outrdy # outack
Rev == CanOutRev /\ outack' = 1 - outack /\ UNCHANGED <<inval,inack,inrdy,outrdy,outval,q>> 

5、下一步动作

Next == \E d \in Message:Send(d)
        \/ BufRev
        \/ BufSend
        \/ Rev
=========================================================================

在上述第4步中,有很多的UNCHANGED 数据,在TLA+的代码中,如果有变量的状态未发生变更,一定要用UNCHANGED 进行标记,否则当前步骤执行完毕后,未使用UNCHANGED标记出来的变量的值将变更为NULL,这将影响到下一步操作的执行。

运行

按下图设置Init,Next,设置Message的范围,然后运行。在这里插入图片描述
上述运行时间会很长,TLC检测到的状态也会很多,主要原因是上述TLA+代码是一个无边界限制的状态搜索,在无边界的状态下,q的值是不定的,在上述例子中,q的值可以是<<1>>,<<1,2>>,<<1,2,2>>,<<1,1,1,1,1,1,1>>等。
如果需要增加边界检查,可以增加q的长度检查,比如限制q的长度小于5。
在上图中TypeInvariant的检查项下面增加Len(q) < 5即可。
在这里插入图片描述
这样程序运行很快就会结束,并通过Error-trace打印出Len(q)==5的过程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值