FSP语言学习之:建立并发模型 Concurrency

并发模型

语法

  • 通过双竖线表示两个进程 P, Q 同步进行
ITCH = (scratch -> STOP).
CONVERSE =(think -> talk -> STOP).
||CONVERSE_ITCH = (ITCH || CONVERSE).

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

数学规则

  • 并发模型满足交换律和结合律

在这里插入图片描述

  • 如果 P, Q 之外还有第三个进程同步进行的话,写成如下形式:
ITCH = (scratch -> STOP).
CONVERSE =(think -> talk -> STOP).
LAUGH = (laugh -> LAUGH).
||CONVERSE_ITCH = (ITCH || LAUGH).
||CONVERSE_ITCH_LAUGH = (CONVERSE_ITCH || LAUGH).
  • CONVERSE_ITCH 先并行了之后,再与 LAUGH 并行

行人过马路案例

行人随意过马路

  • 一个行人可以随时过马路
PEDESTRAIN = (wander -> PEDESTRAIN).
  • 红绿灯在 红绿黄三个颜色之间变化
TRAFFIC_LIGHT = (green -> yellow -> red -> TRAFFIC_LIGHT).
  • 行人如果不管交通灯随意过马路,那么这个程序可以如此模拟:
||LIGHT_PEDESTRIAN = (PEDESTRAIN || TRAFFIC_LIGHT).

在这里插入图片描述

行人按照交通灯过马路

  • 如何让行人按照和交通灯的交互来过马路:

    • 让两个进程之间共享动作(shared actions)
  • 行人在某个时刻会有两种状态:

PEDESTRAIN = (button -> PEDESTRAIN
			 | wander -> PEDESTRAIN).

在这里插入图片描述

  • 交通灯会有下面几种状态:
TRAFFIC_LIGHT = (button -> YELLOW | idle -> GREEN),
GREEN = (green -> TRAFFIC_LIGHT),
YELLOW = (yellow -> RED),
RED = (red -> TRAFFIC_LIGHT).

在这里插入图片描述

  • 当让行人和交通灯之间有交互,状态图如下:
    在这里插入图片描述
  • 在这个过程中,我们发现在这个交互的状态图中没有特别标明是哪个进程在操作 button,因为 button 对两个进程来说是共享的
  • 我们可以很自然的把 button 看做是 pedestrian 的输出,同时也是 traffic_light 的输入。但是对于这个状态图来说,它就仅仅只是一个共享的 action 仅此而已。

动作重标记(Action relabelling)

  • 在上面交通灯——行人的例子中,行人可以选择 button 或者 wander 行为;然而,当行人选择了 wander,那么就预示着交通灯的 button 没有被按下;因此 wanderring 操作和交通灯的 idle(空闲)操作可以看成是一个操作。
  • 在这种情况下我们可以选择更改 TRAFFIC_LIGHTPEDESTRIAN 让这个 action 有同样的名字,但是这并不是一种理想的方式,因为这种重命名的操作可能会导致另外一个复合进程的 break
  • 因此我们采用一种方式—— action relabelling

语法

  • 给定一个进程P, 我们可以用 P/{new1/old1,...,newN, oldN} 来表达和 P 同样的意思,只是 action old1 被改名为了 new1
  • 上面的例子中,我们说 idlewander 是等同的状态,因此,我们将上面的语句可以写成下面的形式:
TRAFFIC_LIGHT = (button -> YELLOW | idle -> GREEN),
GREEN = (green -> TRAFFIC_LIGHT),
YELLOW = (yellow -> RED),
RED = (red -> TRAFFIC_LIGHT).
PEDESTRIAN = ( button -> PEDESTRIAN
| wander -> PEDESTRIAN
).
||LIGHT_PEDESTRIAN =
(TRAFFIC_LIGHT || PEDESTRIAN/{idle/wander}).
  • 前面两个进程中的所有内容都不需要重新编写,只是在两个进程进行并行复合的时候,将 PEDESTRIAN 中的 wander 重标记成 TRAFFIC_LIGHT 中的 idle

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 可以看到,PEDESTRIAN 中的 wander 也被重标记成了 idle

客户机—服务器案例

单个客户机和服务器交互

  • 定义一个客户机:
CLIENT = (call -> wait -> continue -> CLIENT).

在这里插入图片描述

  • 定义一个服务器:
SERVER = (request -> service -> reply -> SERVER).

在这里插入图片描述

  • 同时开启客户机和服务器:
|| CLIENT_SERVER = (CLIENT || SERVER)

在这里插入图片描述

  • 其实服务器和客户机有同时发生的 action,比如服务器的 request 和 客户机的 call 是同时发生的,客户机的 wait 和服务器的 reply 是同时发生的,因此我们替换着两组 action
|| CLIENT_SERVER = (CLIENT || SERVER) /{call/request, reply/wait}.

在这里插入图片描述

  • 可以发现,经过 action relabelling 可以让整个状态简化不少

多个同类进程进行区分

  • 当存在多个客户机,我们自然而然地想写如下的操作语句:
CLIENT = (call -> wait -> continue -> CLIENT).
||TWO_CLIENTS = (CLIENT || CLIENT).
  • 然而,由于所有的 action 在不同的 CLIENT 进程之间都是共享的,因此,这个操作的结果就等同于 CLIENT 本身:
    在这里插入图片描述
    在这里插入图片描述

进程标记(Process labelling)

  • 当有多个相同类型的进程的时候,如果不对进程进行标记,就会出现上述情况,当我们采取进程标记,我们就可以很好的区分多个类型相同的进程。

语法

|| TWO_P = (a:P || b:P)
  • 用在上面的多个 CLIENT 的例子中就是:
CLIENT = (call -> wait -> continue -> CLIENT).
||TWO_CLIENTS = (a:CLIENT || b:CLIENT).

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • Process labelling 就是通过添加 ”前缀“ 的方式来给相同类型的进程加以区分,这样他们就不会共享 action

N 个进程标记

  • 以下三种写法是完全等同的:
const N = 3
CLIENT = (call -> wait -> continue -> CLIENT).
||N_CLIENTS = (c[i:1..N]:CLIENT).
CLIENT = (call -> wait -> continue -> CLIENT).
||N_CLIENTS(N=3) = (c[i:1..N]:CLIENT).
CLIENT = (call -> wait -> continue -> CLIENT).
||N_CLIENTS(N=3) = (forall[i:1..N] c[i]:CLIENT).

在这里插入图片描述

一个 Server 和 多个 client 进程复合

  • 回顾一下前面的内容:

    • 当我们要让两个进程之间产生关联和交互,我们需要采用 action relabelling 来产生联系
    • 当多个同类进程之间进行区分我们通过 process labelling 加前缀来让同类的 process 不能共享。
    • 那么当我们在使用一个 server 和 多个同类的 client 交互的时候,我们既要区分多个同类 client,还要让他们和 server 之间产生关联而对他们的 action relabelling
    • 但是由于多个 client 已经不共享 action 了,难道我们要一个个的把每个 client 中的 action 手动改掉么?当然不是,我们采用前缀集合的方式(prefix set)批量修改 action
  • 例如当只有两个 clientserver 交互,我们如下写:

CLIENT = (call -> wait -> continue -> CLIENT).
SERVER = (request -> service -> reply -> SERVER).
||CLIENT_2 = (a:CLIENT || b:CLIENT || {a,b}::(SERVER/{call/request, wait/reply})).

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 他们复合后的进程状态
    在这里插入图片描述
  • 将这种交互拓展到 N 个同类型的 CLIENTSERVER 交互的情况:
CLIENT = (call -> wait -> continue -> CLIENT).
SERVER = (request -> service -> reply -> SERVER).
||N_CLIENT_SERVER(N=2)
	= (forall [i:1..N] (c[i]:CLIENT)||{c[i:1..N]}::(SERVER/{call/request, wait/reply})).

变量隐藏(Variable hiding)

  • 为了减少系统建模时候的复杂度,经常会通过隐藏一些变量来达到目的。

    • 给定一个进程 P,进程 P\{a1, ..., aN} 表达的意思和进程 P 是完全相同的,但是 a1...aN 这些 action 会被隐藏起来。
    • 能达到隐藏效果的语句还有:P@{a1,...aN};使用 @ 来表示那些不被隐藏的 action,其他的会被隐藏。那些被隐藏起来的状态在图中会用 tau 表示
    • 因此 @ 操作符和 \ 操作符可以认为是互补的
  • 下面的语句效果相同:

SERVER_1 = (request -> service -> reply -> SERVER_1)
@{request , reply}.
SERVER_2 = (request -> service -> reply -> SERVER_2)
\{service}.

在这里插入图片描述
在这里插入图片描述

  • 第一个例子中通过@ 保留了 requestreply action
  • 第二个例子则使用 \ 来隐藏 service
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暖仔会飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值