AsmL实例研究(一)

为了能够对AsmL有一个更加感性的认识,同时也为了了解如何使用AsmL建模,我们不妨来研究一个AsmL的实例。下面这个例子是一个用AsmL写成的设计规格的Word版本,它来自于AsmL2.1.5.8所带的一个例子——DiningPhilosophers。为了便于理解,我将它翻译成了中文。更多的AsmL例子可以在AsmLSample folder中找到。

 

 

Dijkstra的饭桌上的哲学家

FSE

1         Embedding

这个例子是下面这个名字空间的一部分:

namespace DiningPhilosophers

2         Model

一群哲学家坐在桌边。每人的左边和右边各有一个餐叉。我们用下面这个只有一个域index的结构来定义餐叉:

structure Fork

  index as Integer

哲学家被定义成具有唯一的索引,能够反映他们当前所处的状态,以及具有如下两种能力:报告他们是否能够改变状态(canMove),以及能够执行状态的改变(move)。因为status 可以改变,所以哲学家是class而不是structure

abstract class Philosopher

  var status as State = Thinking

  index as Integer

 

  abstract canMove(table as Table) as Boolean

  abstract move(table as Table)

为了简单起见,我们假定哲学家具有固定的数量(5)

numPhilosophers as Integer  = 5

同样,我们有五把餐叉。

numForks as Integer  = numPhilosophers

forks as Set of Fork = {Fork(i) | i in {1..numForks}}

哲学家左边的餐叉与哲学家具有相同的索引。哲学家右边的餐叉的索引比哲学家的索引大(是哲学家总数的模)。

left(p as Philosopher) as Fork

  return Fork(p.index)

 

right(p as Philosopher) as Fork

  return Fork(p.index mod numPhilosophers + 1)

思考中的哲学家没有餐叉。(谁需要一把餐叉来思考?)思考中的哲学家可能变得饥饿。饥饿的哲学家试图得到他左边的餐叉从而变成“左手拿餐叉的饥饿的哲学家”。但是只拿到一把餐叉是不够的,只有得到两把餐叉哲学家才开始吃东西。 而右边的餐叉只有在没有人用时才能被得到。吃完东西之后,哲学家只有一件事可以做,那就是放下两把餐叉继续思考。所以,一个成功的哲学家吃一次东西的过程是这样的: Thinking -> Hungry -> HungryWithLeftFork -> Eating -> Thinking

enum State

  Thinking

  Hungry

  HungryWithLeftFork

  Eating

我们现在为这五位哲学家定义一张桌子:

class Table

  philosophers as Set of Philosopher

用一个变量来描述哪把餐叉正被哪个哲学家使用。另一个变量定义了一个正在吃东西的哲学家的集合:

class Table

  var holder as Map of Fork to Philosopher = { -> }

  var fed as Set of Philosopher = {}

下面的方法描述了哲学家的动作。能够动作的哲学家是随机选取的。如果没有哲学家能够动作,那么一个死锁发生了。

class Table

  var stepNo as Integer = 0

  [EntryPoint]

  Move()

    choose phil in philosophers where phil.canMove(me)

      phil.move(me)

      stepNo := stepNo + 1

EntryPoint使得被标记的方法能够被外部世界调用,例如可以被C#调用。

2.1      Greedy Philosophers

贪婪的哲学家在吃完东西并开始思考之前绝不会放下餐叉,这会导致死锁。

class GreedyPhilosopher extends Philosopher

  override move(table as Table)

    match status

      Thinking : status := Hungry

      Hungry   : if not (left(me) in table.holder)

                   table.holder(left(me)) :=

                                    me as Philosopher

                   status := HungryWithLeftFork

      HungryWithLeftFork

               : if not (right(me) in table.holder)

                   table.holder(right(me)) :=

                                    me as Philosopher

                   status := Eating

                   add me to table.fed

      Eating   : remove table.holder(left(me))

                 remove table.holder(right(me))

                 status := Thinking

canMove方法指出哲学家是否能够改变状态:

class GreedyPhilosopher

  override canMove(table as Table) as Boolean

    return status = Thinking

        or (status = Hungry and

            left(me) notin table.holder)

        or (status = HungryWithLeftFork and

            right(me) notin table.holder)

        or status = Eating

2.2      Generous Philosophers

慷慨的哲学家并不坚持一定要有一个成功的哲学家的生活。在拿到左手的叉子之后,如果发现无法得到右手的餐叉,慷慨的哲学家就会放下左手的餐叉,继续思考一会。因此,如果所有人都是慷慨的哲学家,那么不会有死锁,但是有可能有人饿死。:)

class GenerousPhilosopher extends Philosopher

  override move(table as Table)

    match status

      Thinking : status := Hungry

      Hungry   : if not (left(me) in table.holder)

                   table.holder(left(me)) :=

                                       me as Philosopher

                   status := HungryWithLeftFork

      HungryWithLeftFork

               : if not (right(me) in table.holder)

                     table.holder(right(me)) :=

                                       me as Philosopher

                     status := Eating

                     add me to table.fed

                 else

                   // someone else is holding the

                   // right fork

                   // put the left one down and

                   // try again another time

                   remove table.holder(left(me))

                   status := Thinking

      Eating   : remove table.holder(left(me))

                 remove table.holder(right(me))

                 status := Thinking

注意,决定慷慨的哲学家的状态能否改变的条件要比贪婪的哲学家宽松。

class GenerousPhilosopher

  override canMove(table as Table) as Boolean

    return status = Thinking

        or (status = Hungry and

            left(me) notin table.holder)

        or status = HungryWithLeftFork

        or status = Eating

3         Providing the View

我们提供两个方法来初始化,一个初始化贪婪的哲学家,另一个初始化慷慨的哲学家。

class Table

  [EntryPoint]

  shared InitGreedy() as Table

    philosophers = { new GreedyPhilosopher(i) as Philosopher |

                        i in [1..numPhilosophers] }

    return new Table(philosophers)

 

  [EntryPoint]

  shared InitGenerous() as Table

    philosophers = { new GenerousPhilosopher(i) as Philosopher |

                        i in [1..numPhilosophers] }

    return new Table(philosophers)

给出哲学家的索引,下面的方法将指出该哲学家拿有餐叉,以及是否正在吃东西。

class Table

  HoldsLeft(pIndex as Integer) as Boolean

    return exists (i,p) in holder where p.index = pIndex and

                                        left(p) = i

 

  HoldsRight(pIndex as Integer) as Boolean

    return exists (i,p) in holder where p.index = pIndex and

                                        right(p) = i

 

  IsFeeded(pIndex as Integer) as Boolean

    return exists p in fed where p.index = pIndex

 

  IsDeadlock() as Boolean

    return forall p in philosophers holds not p.canMove(me)

 

  IsGreedy() as Boolean

    return exists p in philosophers where p is GreedyPhilosopher

 

  StepNo() as Integer

    return stepNo

   

 

本文旨在引介 AsmL 。由于作者也刚刚接触 AsmL 不久,文中的错误与疏漏之处在所难免。如遇不明之处,相信能够从微软研究院的相关网站上找到答案。如果您还不清楚AsmL是什么,您可以参考作者之前的一篇文章《AsmL:可执行的软件规格》。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值