AsmL实例研究(一)

    技术2022-05-11  60

    为了能够对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)