Инструменты пользователя

Инструменты сайта


ao2004

Различия

Здесь показаны различия между двумя версиями данной страницы.

Ссылка на это сравнение

ao2004 [2019/11/08 19:54] (текущий)
иван_денисов создано
Строка 1: Строка 1:
 +====== Сообщение о языке Active Oberon ======
  
 +Patrik Reali *
 +
 +27 октября 2004 г.
 +
 +Перевод Андреева М.В. опубликован с согласия автора. [[http://​maxandreev.narod.ru/​oberon/​ActiveOberonReport_RUS.html|Оригинал]]
 +
 +===== 1 Введение =====
 +
 +**Active Oberon**((информация в [[https://​ru.wikipedia.org/​wiki/​%D0%90%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9_%D0%9E%D0%B1%D0%B5%D1%80%D0%BE%D0%BD|Википедии]])) является расширением оригинального языка **Oberon** [29, 30]. Его цель — введение в язык свойств для выражения параллелизма посредством //​активных объектов//​ (active objects((для более подробной информации смотрите [[https://​ru.wikipedia.org/​wiki/​Active_Object]])) ). Данный отчет предполагает знакомство с языком **Oberon**; описываются только расширения языка.
 +
 +Проектирование расширения языка направлялось на достижение унификации и гармонии. Изменения основаны на устоявшихся концепциях,​ таких как область действия и локальность. Обоснования,​ выходящие за рамки **Active Oberon**, описаны в [10].
 +
 +==== 1.1 Благодарности ====
 +
 +
 +Большое спасибо **B. Kirk, A. Fischer, T. Frei, J. Gutknecht, D. Lightfoot**,​ и **P. Muller** за рецензию данного документа,​ за внесение поправок и улучшений,​ а так же **Владимиру Лосю** за усовершенствование примера <<​барьер>>​.
 +
 +==== 1.2 Предыстория и родственные работы ====
 +
 +Разработка языков программирования в **ETH Zurich** имеет богатые традиции. Язык **Oberon** — это последний наследник семейства **Algol, Pascal** и **Modula**. **Pascal** [16] задумывался как язык для представления маленьких программ;​ простота и компактность сделали его особенно подходящим для обучения программированию. **Modula** [28] эволюционировала из **Pascal** как язык для системного программирования,​ и извлекла пользу из практического опыта, полученного при проектировании рабочей станции **Lilith** [22] и операционной системы **Medos** [17]. Необходимость поддержки парадигмы «программирования в большом» была стимулом для создания **Oberon** [29]. Платформы **Ceres** [6] и **Chameleon** [12], //​операционная система//​ **Oberon** [11] — эти проекты разрабатывались параллельно с проектированием языка, что позволило испытать и оценить его удобство.
 +
 +Множество расширений языка **Oberon** было предложено как в **ETH**, так и вне его. **Object Oberon** [19], **Oberon-2** [18], и **Froderon** [7] исследуют добавление дополнительных объектно-ориентированных свойств в язык; **Oberon-V** [9] предлагает дополнения для поддержки параллельных операций на векторных компьютерах;​ **Oberon-XSC** [15] добавляет математические возможности для поддержки научных вычислений;​ также было предложено встраивание модулей [24]. //​Параллелизм//​ был впервые добавлен в операционную систему через специальный системный **API** в **Concurrent Obero**n [25] и **XOberon** [2]; попытка моделирования параллелизма средствами самого языка была предпринята **Radenski** [23].
 +
 +{{ ::​activeoberonreport_rus0x.png?​nolink&​400 |}}
 +
 +Рис. 1: Эволюция языков семейства Pascal
 +
 +**Active Oberon** — это первый представитель нового поколения языков в данном семействе. Мы старались добавить в язык поддержку параллелизма и моделирования компонентов ясным и безболезненным способом.
 +
 +==== 1.3 Дизайн языка ====
 +
 +На дизайн **Active Oberon** повлиял опыт, полученный при проектировании **Oberon** и **Oberon-2**. Мы следуем нотации **Object Oberon** для объявления классов и методов,​ т. к. считаем,​ что данный способ выразительнее нотации **Oberon-2**:​ методы принадлежат классу и, следовательно,​ должны быть объявлены в классе;​ таким образом,​ прочие методы и поля, лежащие в области видимости записи,​ могут быть доступны без указания спецификатора. Защита от одновременного доступа при помощи модификатора ''​EXLUSIVE''​ более читабельна,​ если методы принадлежат одной области видимости. **Active Oberon** отходит от дизайна **Object Oberon** в том, что записи одновременно являются так же и классами,​ т. е. не позволяется сосуществование классов и записей в одной системе. Другое важное отличие продиктовано решением позволить компилятору обрабатывать //​опережающие ссылки//​ (forward reference). Синтаксис **Object Oberon** и **Oberon-2** разработан в том числе и с целью упрощения создания компилятора,​ мы же постарались упростить работу программистов путем исключения ненужной избыточности опережающих объявлений,​ переложив тем самым работу на плечи компилятора.
 +
 +**Java** [8] и **C#** [4] разделяют некоторые похожие идеи с **Active Oberon**. Они так же являются объектно-ориентированными языками из мира императивных языков,​ и механизм защиты экземпляров объектов от одновременного доступа так же связан с мониторами. С другой стороны,​ они делают акцент на объектно-ориентированноcти в такой экстремальной манере,​ что методы и поля класса трактуются как частный случай методов и полей экземпляра объекта,​ т. к. они лежат в пространстве имен класса. Более того, в **Jav**a нет //​полноценной//​ поддержки для статического размещения структур:​ все структуры размещаются в динамической памяти,​ даже определенные пользователем массивы констант;​ поэтому,​ что бы получить приемлемую скорость исполнения,​ программы **Java** //​нуждаются//​ в использовании сложной и затратной оптимизации при компиляции. Все языки из семейства //Oberon// рассматривают модули и классы как //​ортогональные понятия//,​ каждое из них обладает своей областью действия;​ семантика модуля отличается от семантики класса так, как показано в [26] (для сравнения,​ **B. Meyer** защищает противоположное мнение [18]): модули группируют статические компоненты и соответствующие реализации,​ и предоставляют примитивы для развертывания и структурирования. На деле **Java** и **C#** вводят концепции,​ такие как //​пакеты//​ (packages), //​пространства имен// (namespaces) и //​сборки//​ (assemblies),​ которые //​фактически//​ являются //​модулями//,​ но только под другим именем. Мы думаем,​ что все еще остаются веские причины для того, что бы статические структуры и модули были частью языка программирования.
 +
 +Оператор ''​AWAIT''​ предложен и исследован **Brinch Hansen** [3], который показал его //​концептуальную простоту//​ и элегантность,​ но в то же время думал, что его нельзя реализовать эффективно. Мы снова предлагаем этот оператор в **Active Oberon** с уверенностью,​ что это значительное усовершенствование по сравнению с сигналами и семафорами потому,​ что он вносит унификацию и ясность;​ это становится особенно очевидно при программировании в объектно-ориентированном стиле, для которого сигналы и семафоры //​совершенно не подходят//​ в виду их неструктурного использования,​ т. к. они могут быть добавлены в программы //​совершенно произвольным//​ образом. В диссертации **Питера Мюллера** (Pieter Muller) [21] доказывается,​ что, при определенных ограничениях,​ оператор ''​AWAIT''​ //​может//​ быть реализован эффективно. Язык **Ada 95** [14] тоже использует конструкт,​ названный //​барьеры//​ (barriers), который семантически весьма похож на ''​AWAIT''​ в **Active Oberon**, но только с детализацией на уровне процедур.
 +
 +**Concurrent Oberon** был первой попыткой реализовать параллелизм в системе **Oberon**. Это было сделано через специальный **API**, определяющий тип ''​Thread''​ и функции для создания,​ остановки и возобновления исполнения. Защита была реализована при помощи одного глобального //​системного замка//​ (system lock). Но не были предложены примитивы синхронизации. Эта модель так же слаба для **Active Oberon**, т. к. блокировки и синхронизация тесно связаны (когда выполняется синхронизация,​ блокировка снимается),​ и блокирующий механизм //​слишком грубый//;​ один замок сделает мультипроцессорную систему (в которой множество процессов исполняется одновременно) //​бесполезной//​.
 +
 +===== 2 Объектно-ориентированные расширения =====
 +
 +==== 2.1 Указатель на безымянные типы записей ====
 +
 +<code oberon2>
 +TYPE  ​
 +  (* пример указателя на безымянные типы записей *)  ​
 + 
 +  (* указатели на именованные типы записей *)  ​
 +  Tree = POINTER TO TreeDesc;  ​
 +  TreeDesc = RECORD key: INTEGER; l, r: Node END;  ​
 + 
 +  (* указатели на безымянные типы записей *)  ​
 +  Node = POINTER TO RECORD key: INTEGER; next: Node END;  ​
 +  DataNode = POINTER TO RECORD (Node) data: Data END;  ​
 +  DataTree = POINTER TO RECORD (Tree) data: Data END;
 +</​code>​
 +
 +Типы ''​Node''​ и ''​DataNode''​ — //​указатели на безымянные типы записей//​ (pointers to anonymous record types); ''​Tree''​ — //​указатель на именованный тип записей//​ (pointer to named record type).
 +
 +//​Экземпляры//​ данных типов могут быть размещены //​только//​ в динамической памяти (при помощи ''​NEW''​),​ статические экземпляры не доступны;​ это вызвано тем, что тип записей безымянный и невозможно определить переменную этого типа.
 +
 +Типы ''​RECORD''​ и ''​POINTER TO RECORD''​ могут быть базовыми типами для указателя на безымянный тип записей;​ тип записей //не может//​ расширить указатель на анонимную запись,​ таким образом выполняется свойство,​ разрешающее //​только//​ динамические экземпляры.
 +
 +==== 2.2 Объектные типы ====
 +
 +<code oberon2>
 +TYPE  ​
 +  (* объектные типы *)  ​
 +  DataObj = OBJECT VAR data: Data; l, r: DataObj END DataObj;
 +</​code>​
 +
 +''​DataObj''​ — это //​объектный тип// (object type).
 +
 +Синтаксис типа ''​OBJECT''​ отличается от синтаксиса типа ''​POINTER TO RECORD'';​ он должен следовать правилу [ DeclSeq ] Body вместо правила ''​FieldList''​. Это подразумевает,​ что процедуры могут быть объявлены //​внутри//​ объектного типа. Мы называем их //​методы//​ (methods) или //​связанные с типом процедуры//​ (type-bound procedures).
 +
 +Только //​объектный//​ тип //​может расширить другой объектный тип//. //​Экземпляры//​ объектных типов должны размещаться динамически при помощи ''​NEW'',​ подчиняясь правилу,​ продиктованному инициализаторами (Раздел 2.4).
 +==== 2.3 Связанные с типом процедуры ====
 +
 +<code oberon2>
 +TYPE  ​
 +  Coordinate = RECORD x, y: LONGINT END;  ​
 + 
 +  VisualObject = OBJECT  ​
 +    VAR next: VisualObject;  ​
 + 
 +    PROCEDURE Draw*; (*нарисовать данный объект*)  ​
 +    BEGIN HALT(99); (*заставить расширения переопределять этот метод*)  ​
 +    END Draw;  ​
 +  END VisualObject;  ​
 + 
 +  Point = OBJECT (VisualObject)  ​
 +    VAR pos: Coordinate;  ​
 + 
 +    PROCEDURE Draw*; (*перекрываем метод Draw, объявленный в VisualObject*)  ​
 +    BEGIN MyGraph.Dot(pos.x,​ pos.y)  ​
 +    END Draw;  ​
 +  END Point;  ​
 + 
 +  Line = OBJECT (VisualObject)  ​
 +    VAR pos1, pos2: Coordinate;  ​
 + 
 +    PROCEDURE Draw*;  ​
 +    BEGIN MyGraph.Line(pos1.x,​ pos1.y, pos2.x, pos2.y)  ​
 +    END Draw;  ​
 +  END Line;  ​
 + 
 +VAR  ​
 +  objectRoot: VisualObject;  ​
 + 
 +PROCEDURE DrawObjects*;  ​
 +  VAR p: GraphObject;  ​
 +BEGIN  ​
 +  (* рисуем все объекты из списка *)  ​
 +  p := objectRoot;  ​
 +  WHILE p # NIL DO p.Draw; p := p.next END;  ​
 +END DrawObjects;​
 +</​code>​
 +
 +//​Процедуры//,​ объявленные внутри объекта,​ называются //​связанные с типом процедуры//​ (type-bound procedures) или методы (methods). //​Методы//​ ассоциируются с экземпляром типа и оперируют им; внутри реализации метода,​ если другой метод виден по правилам видимости **Oberon**, то он доступен без указания квалификатора. Метод может //​перекрывать//​ другой метод с таким же названием унаследованный //от базового типа// записей,​ но при этом он должен обладать //​такой же сигнатурой//​. Признак видимости является частью сигнатуры.
 +
 +**Замечание**:​ Мы решили объявлять методы в области видимости объекта потому,​ что они принадлежат области видимости записи и могут быть доступны только через экземпляры записи. Это упрощает определение методов (нет получателя как в **Oberon-2** [20]) и доступ к полям и методам следует хорошо известным правилам видимости **Oberon**. Мы боялись того, что циклические ссылки станут проблемой (например,​ два объектных типа //​взаимно ссылаются//​ друг на друга),​ но решили,​ что концептуальная элегантность языка //​более важна//​. Решение проблемы в //​ослаблении//​ правил видимости — //​допустить опережающие ссылки//​ на символы,​ объявленные позднее в исходном тексте (раздел 4.1). Альтернативный способ заключается в //​расширении//​ опережающих описаний до описания всего типа (как в **Object Oberon** [19]). Мы отвергли данное решение в виду внесения //​ненужной избыточности//​ в код и вместо этого переложили решение проблемы на компилятор.
 +
 +Дан экземпляр объекта o типа ''​T''​ со связанными процедурами ''​P''​ и ''​Q'',​ ''​o.P''​ — это //​вызов//​ метода. Внутри метода типа ''​T''​ другой метод типа ''​T''​ может быть вызван как ''​Q''​. Метод ''​P''​ может вызвать метод, который он перекрывает,​ как ''​P↑''​ . Это //​супервызов//​ и он может быть выполнен только //​внутри//​ метода.
 +
 +==== 2.4 Инициализаторы ====
 +
 +Метод, помеченный символом ''&''​ , является //​инициализатором объекта//​ (object initializer). Этот метод вызывается автоматически при создании экземпляра объекта. Объектный тип может иметь //не более одного//​ инициализатора. Если он есть, он //​всегда//​ общедоступен и может быть вызван //​явно//,​ как метод; если отсутствует,​ то наследуется инициализатор базового типа. Инициализатор может иметь сигнатуру //​отличающуюся//​ от сигнатуры унаследованного инициализатора базового типа, но в этом случае наименование инициализатора так же //​должно//​ отличаться.
 +
 +Если объектный тип ''​T''​ содержит или наследует инициализатор ''​P''​ с сигнатурой (p0: T0; .... pn: Tn), тогда конкретизация переменной ''​o:​T''​ при помощи ''​NEW''​ требует указать параметры инициализатора:​ ''​NEW(o,​ p0, ..., pn)''​. Инициализатор исполняется автоматически вместе с ''​NEW''​.
 +
 +**Замечание**:​ Необязательный инициализатор делает возможным параметризацию типа. В частности,​ это весьма удобно при работе с //​активными объектами//,​ т .к. параметризация экземпляра должна быть выполнена //до старта//​ активности. Если на чистоту,​ то нам такая нотация //не нравится//,​ но это единственный способ,​ который мы смогли придумать,​ добавить свойство //не меняя сам язык//.
 +
 +<code oberon2>
 +TYPE  ​
 +  Point = OBJECT (VisualObject)  ​
 +    VAR pos: Coordinate;  ​
 + 
 +    PROCEDURE & InitPoint(x,​ y: LONGINT);  ​
 +    BEGIN pos.x := x; pos.y := y  ​
 +    END InitPoint;  ​
 + 
 +  END Point;  ​
 + 
 +  PROCEDURE NewPoint(): Point;  ​
 +    VAR p: Point;  ​
 +  BEGIN NEW(p, x, y); (* вызывает NEW(p) и p.InitPoint(x,​ y) *)  ​
 +    RETURN p  ​
 +  END NewPoint;
 +</​code>​
 +
 +==== 2.5 SELF ====
 +
 +Ключевое слово ''​SELF''​ может быть использовано в //​любом//​ методе или в любой локальной процедуре метода объекта. Тип данной переменной совпадает с типом объекта и ее значение //​равно экземпляру//​ объекта,​ к которому привязан метод. Переменная используется для доступа к объекту в случае,​ если нужна ссылка на объект или когда поле или метод объекта перекрывается другим символом,​ например,​ поле записи перекрывается локальной переменной с тем же именем.
 +
 +<code oberon2>
 +TYPE  ​
 +  ListNode = OBJECT  ​
 +    VAR data: Data; next: ListNode;  ​
 + 
 +    PROCEDURE & InitNode (data: Data);  ​
 +    BEGIN  ​
 +      SELF.data := data; (* инициализируем данные объекта *)  ​
 +      next := root; root := SELF (* добавляем node в начало списка *)  ​
 +    END InitNode;  ​
 +  END ListNode;  ​
 + 
 +VAR  ​
 +  root: ListNode;
 +  </​code>​
 +
 +==== 2.6 Делегаты ====
 +<code oberon2>
 +TYPE  ​
 +  MediaPlayer = OBJECT  ​
 +    PROCEDURE Play; .... показать фильм .... END Play;  ​
 +    PROCEDURE Stop; .... остановить фильм .... END Stop;  ​
 +  END MediaPlayer;  ​
 + 
 +  ClickProc = PROCEDURE {DELEGATE};  ​
 + 
 +  Button = OBJECT  ​
 +    VAR  ​
 +      onClick: ClickProc;  ​
 +      caption: ARRAY 32 OF CHAR;  ​
 + 
 +      PROCEDURE OnClick;  ​
 +      BEGIN onClick END OnClick;  ​
 + 
 +      PROCEDURE & Init(caption:​ ARRAY OF CHAR; onClick: ClickProc);  ​
 +      BEGIN SELF.onClick := onClick; COPY(caption,​ SELF.caption)  ​
 +      END Init;  ​
 +  END Button;  ​
 + 
 +  PROCEDURE Init(p: MediaPlayer);  ​
 +    VAR b0, b1, b2: Button;  ​
 +  BEGIN  ​
 +    (* Перезагрузка -> вызвать системную функцию *)  ​
 +    NEW(b0, "​Reboot",​ System.Reboot);  ​
 + 
 +    (* Интерфейс MediaPlayer:​ связываем кнопки с экземпляром плеера *)  ​
 +    NEW(b1, "​Play",​ p.Play);  ​
 +    NEW(b2, "​Stop",​ p.Stop);  ​
 +  END Init;
 +  </​code>​
 +
 +//​Делегаты//​ подобны процедурным типам; они совместимы как с процедурами так и с методами,​ в то время как процедурные типы совместимы //​только//​ с процедурами.
 +
 +//​Делегаты процедурных типов//​ помечаются модификатором ''​DELEGATE''​. Делегатам могут быть назначены процедуры и методы. Пусть даны переменная с процедурным типом ''​t'',​ экземпляр объекта ''​o''​ и метод ''​M''​ связанный с ''​o'',​ тогда можно записать ''​o.M''​ в ''​t'',​ если конечно метод и ''​t''​ обладают совместимыми сигнатурами. Ссылка на сам объект исключается из сигнатуры процедурного типа. Всякий раз при вызове ''​t''​ назначенный объект o явно передается в self-ссылку (self-reference). Присваивания и вызовы процедур остаются совместимыми с описанием **Oberon**.
 +
 +==== 2.7 Описания (definitions) ====
 +
 +
 +//​Описание//​ (definition) — это синтаксический контракт 1, определяющий набор сигнатур методов. Описание ''​D0''​ может быть уточнено новым описанием ''​D1'',​ которое наследует все методы,​ объявленные в ''​D0''​. Описания и их методы видимы //​глобально//​. Объект может реализовать одно или несколько описаний,​ в этом случае он обязуется реализовать все методы определенные в этих описаниях.
 +
 +<code oberon2>
 +DEFINITION Runnable;  ​
 +  PROCEDURE Start;  ​
 +  PROCEDURE Stop;  ​
 +END Runnable;  ​
 + 
 +DEFINITION Preemptable REFINES Runnable;  ​
 +  PROCEDURE Resume;  ​
 +  PROCEDURE Suspend;  ​
 +END Preemptable;  ​
 + 
 +TYPE  ​
 +  MyThread = OBJECT IMPLEMENTS Runnable;  ​
 +    PROCEDURE Start;  ​
 +    BEGIN .... END Start;  ​
 + 
 +    PROCEDURE Stop;  ​
 +    BEGIN .... END Stop;  ​
 +  END MyThread;
 +  </​code>​
 +
 +Ключевое слово ''​IMPLEMENTS''​ используется для указания описаний,​ реализованных объектным типом. Объектный тип может реализовать //​несколько//​ описаний.
 +
 +Описания можно понимать как //​дополнительные свойства//,​ которыми //​должен//​ обладать объект,​ но которые ортогональны иерархии типов объектов. Метод объекта может быть вызван через описание,​ в этом случае во время исполнения проверяется,​ действительно ли экземпляр объекта реализует описание,​ и только после этого вызывается метод; если экземпляр объекта не реализует описание,​ то возникает //​исключение//​ (run-time exception).
 +
 +<code oberon2>
 +PROCEDURE Execute(o: OBJECT; timeout: LONGINT);  ​
 +BEGIN  ​
 +  Runnable(o).Start;  ​
 +  Delay(timeout);  ​
 +  Runnable(o).Stop;  ​
 +END Execute;
 +</​code>​
 +
 +===== 3 Поддержка параллелизма =====
 +
 +
 +==== 3.1 Активные объекты ====
 +
 +Определение объекта может включать ''​StatBlock'',​ названное //​телом объекта//​ (object body). Тело --- это активность объекта,​ которая исполняется после того, как экземпляр объекта размещен и инициализатор (если он есть) завершил свое исполнение;​ тело объекта помечается модификатором ''​ACTIVE''​. Во время размещения объекта так же размещается новый процесс,​ который исполняет тело //​параллельно//;​ такой объект называется //​активным объектом//​ (active object).
 +
 +Если не указан модификатор ''​ACTIVE'',​ тело исполняется //​синхронно//;​ выход из ''​NEW''​ происходит только после того, как исполнение тела объекта завершается.
 +
 +Система сохраняет явные ссылки на активные объекты до завершения исполнения активности для того, чтобы избежать утилизацию объекта в процессе сборки мусора. Объект //​может//​ пережить свою активность.
 +
 +<code oberon2>
 +TYPE
 +  (* определяем объект и его поведение *)  ​
 +  Object = OBJECT  ​
 +  BEGIN {ACTIVE} (* тело объекта *)  ​
 +    ... делаем что-либо ...  ​
 +  END Object;  ​
 + 
 +  PROCEDURE CreateAndStartObject;  ​
 +    VAR o: Object;  ​
 +  BEGIN  ​
 +    ... NEW(o); ...  ​
 +  END CreateAndStartObject;​
 +  </​code>​
 +
 +//​Активность объекта//​ завершается //​после//​ завершения исполнения //​тела//​ объекта. Пока исполняется тело, объект продолжает существовать (например,​ он не может быть утилизирован при сборе мусора). После этого объект становится пассивным и может быть утилизирован в соответствии с обычными правилами.
 +
 +==== 3.2 Защита ====
 +
 +''​Statement Block''​ --- это последовательность операторов,​ заключенная между ''​BEGIN''​ и ''​END''​. Он может использоваться в любом месте как и простой оператор. Более полезно использовать его вместе с модификатором ''​EXCLUSIVE''​ для создания критической области для защиты операторов от одновременного исполнения.
 +
 +<code oberon2>
 +PROCEDURE P;  ​
 +  VAR x, y, z: LONGINT;  ​
 +BEGIN  ​
 +  x := 0;  ​
 +  BEGIN  ​
 +    y := 1  ​
 +  END;  ​
 +  z := 3  ​
 +END P;
 +</​code>​
 +
 +Объект может рассматриваться как ресурс и различные активности могут потенциально соревноваться за его использование или за эксклюзивный доступ к предоставляемым им средствам;​ в таком случае защита доступа //​необходима//​. Наша модель защиты --- //​монитор//,​ размещенный в экземпляре объекта (instance-based monitor.).
 +<code oberon2>
 +(* Процедуры Set и Reset взаимно исключаемы *)  ​
 +TYPE  ​
 +  MyContainer = OBJECT  ​
 +    VAR x, y: LONGINT; (* Инвариант:​ y = f(x) *)  ​
 + 
 +    PROCEDURE Set(x: LONGINT);  ​
 +    BEGIN {EXCLUSIVE} (* изменение x и y атомарно *)  ​
 +      SELF.x := x; y := f(x)  ​
 +    END Set;  ​
 + 
 +    PROCEDURE Reset;  ​
 +    BEGIN  ​
 +      ...  ​
 +      BEGIN {EXCLUSIVE} (* изменение x и y атомарно *)  ​
 +        x := x0; y := y0;  ​
 +      END;  ​
 +      ....  ​
 +    END Reset;  ​
 +  END MyContainer
 +</​code>​
 +
 +Каждый экземпляр объекта защищен и единицей защиты является произвольный блок операторов от отдельного оператора до целого метода. Блок операторов может быть защищен от одновременного доступа при помощи модификатора ''​EXLUSIVE''​. Активность остается на входе в эксклюзивный блок до тех пор, пока другая активность находится в эксклюзивном блоке того же экземпляра объекта.
 +
 +Активность //не может//​ заблокировать объект //​более одного//​ раза, повторный вход //не допускается//​.
 +
 +Каждый модуль считается объектным типом с //​единственным//​ экземпляром (singleton instance), таким образом его процедуры тоже могут быть защищены. Областью видимости защиты является //​модуль целиком//​ как и в случае //​мониторов//​ [13].
 +
 +**Замечание**:​ Реализована только ''​EXCLUSIVE''​ блокировка:​ ''​SHARED''​ блокировки (как это описано в [10]) могут быть реализованы через ''​EXCLUSIVE''​ блокировки и соответственно не являются базовой концепцией. Они используются очень редко и их реализация //не оправдывает//​ усложнение языка. Реализация ''​SHARED''​ блокировок описана в Приложении B.1.
 +
 +**Замечание**:​ Повторный вход в блокировку не поддерживается из-за //​концептуальной нечистоты//​ (см. [27]) и его корректная обработка стоит //​дорого//;​ в нем нет реальной необходимости,​ т. к. можно проектировать программы без его использования. Повторно-входимые блокировки могут быть реализованы при помощи простых блокировок (см. Приложение B.3).
 +
 +==== 3.3 Синхронизация ====
 +<code oberon2>
 +TYPE  ​
 +  Synchronizer = OBJECT  ​
 +    awake: BOOLEAN  ​
 + 
 +    PROCEDURE Wait;  ​
 +    BEGIN {EXCLUSIVE} AWAIT(awake);​ awake := FALSE  ​
 +    END Wait;  ​
 + 
 +    PROCEDURE WakeUp;  ​
 +    BEGIN {EXCLUSIVE} awake := TRUE  ​
 +    END WakeUp;  ​
 +  END Synchronizer;​
 + </​code>​
 +
 +Встроенная процедура ''​AWAIT''​ используется для синхронизации активности с состоянием системы. Аргументом ''​AWAIT''​ может быть только //​логическое условие//;​ активность сможет продолжить свое выполнение только после того, как условие станет истинным. Пока условие не выполняется,​ активность остается //​приостановленной//​ (suspended);​ если это происходит внутри защищенного блока, то блокировка снимается на время приостановки активности (что позволяет другим активностям изменять состояние объекта и сделать условие истинным);​ активность возобновляет работу только если она сможет снова захватить блокировку.
 +
 +Система отвечает за проверку условий и за возобновление работы приостановленных активностей. Условия внутри экземпляра объекта перепроверяются в случае,​ когда некоторая активность выходит из защищенного блока того же самого экземпляра объекта. Это означает,​ что изменение состояния объекта вне защищенного блока не приводит к перевычислению условия.
 +
 +Когда несколько активностей соревнуются за одну и ту же блокировку,​ то активности с выполненными условиями рассматриваются раньше тех, которые только хотят войти в защищенную область.
 +
 +Приложение B.6 демонстрирует синхронизацию внутри разделяемого буфера.
 +
 +**Замечание**:​ Синхронизация //​зависит//​ от состояния объекта,​ например,​ ожидание доступности некоторых данных или состояния для изменения. Объект используется как контейнер для данных и любой доступ осуществляется через защищенные методы или блоки. Мы подразумеваем,​ что при каждом доступе к защищенному блоку происходит изменение состояния объекта;​ таким образом условия перепроверяются только в этот момент. Это означает,​ что изменение состояния объекта вне защищенного блока не приводит к перевычислению условия. Для принудительной проверки условий можно вызвать пустой защищенный метод или войти в пустой защищенный блок.
 +
 +===== 4 Прочие расширения языка =====
 +
 +В данном разделе описываются несколько важных изменений,​ сделанных для лучшего интегрирования расширений в язык.
 +
 +==== 4.1 Последовательность определений и опережающие ссылки ====
 +
 +В **Active Oberon** область видимости описания символа распространяется на весь блок, содержащий его. Это означает,​ что символ может быть использован до своего определения,​ и что имена уникальны внутри области видимости.
 +
 +==== 4.2 HUGEINT ====
 +
 +В язык был добавлен 64 битный знаковый целый тип ''​HUGEINT''​. Он вписывается в иерархию числовых типов следующим образом:​
 +
 +''​LONGREAL''​ ⊇ ''​REAL''​ ⊇ ''​HUGEINT''​ ⊇ ''​LONGINT''​ ⊇ ''​INTEGER''​ ⊇ ''​SHORTINT''​
 +
 +Имя Тип аргумента Тип результата
 +
 +Функция
 +
 +''​SHORT(x)''​ ''​HUGEINT''​ ''​LONGINT''​
 +
 +идентичность (возможно усечение)
 +
 +''​LONG(x)''​ ''​LONGINT''​ ''​HUGEINT''​
 +
 +идентичность
 +
 +''​ENTIERH(x)''​ вещественный ''​HUGEINT''​
 +
 +наибольшее целое, не превышающее x
 +
 +Таблица 1: Новые процедуры изменения типа
 +
 +Таблица 1 показывает новые процедуры для изменения типа. Никаких новых правил описания констант не вводится;​ константы типизируются в соответствии с их значением.
 +
 +
 +Имя Функция
 +
 +PUT8(adr: LONGINT; x: SHORTINT) Mem[adr] := x
 +PUT16(adr: LONGINT; x: INTEGER)
 +PUT32(adr: LONGINT; x: LONGINT)
 +PUT64(adr: LONGINT; x: HUGEINT)
 +
 +GET8(adr: LONGINT): SHORTINT RETURN Mem[adr]
 +GET16(adr: LONGINT): INTEGER
 +GET32(adr: LONGINT): LONGINT
 +GET64(adr: LONGINT): HUGEINT
 +
 +PORTIN(port:​ LONGINT; x: AnyType) x := IOPort(port)
 +PORTOUT(port:​ LONGINT; x: AnyType) IOPort(port) := x
 +
 +CLI отключить прерывания
 +STI включить прерывания
 +
 + PUTREG/​GETREG константы
 +EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP 32-битовые регистры
 +AX, BX, CX, DX, SI, DI 16-битовые регистры
 +AL, AH, BL, BH, CL, CH, DL, DH 8-регистры
 +
 +
 +Таблица 2: Новое в модуле ''​SYSTEM''​ для ''​IA32''​
 +
 +==== 4.3 Нетрассируемые указатели (untraced pointers) ====
 +
 +//​Нетрассируемые указатели//​ --- это указатели,​ которые //не отслеживаются//​ сборщиком мусора. Структура или объект,​ на которые ссылаются только //​нетрассируемые указатели//,​ могут быть в любой момент утилизированы сборщиком мусора.
 +
 +Нетрассируемые указатели определяются при помощи модификатора ''​UNTRACED''​.
 +''​TYPE Untraced = POINTER {UNTRACED} TO T;''​
 +
 +==== 4.4 Новое для IA32 ====
 +
 +
 +Функции из таблицы 2 были добавлены в компилятор для платформы **Intel IA32**.
 +
 +''​PUTx''​ и ''​GETx''​ были добавлены ради безопасности,​ для работы с //​нетипизированными константами//​.
 +
 +==== 4.5 Прочее ====
 +
 +Некоторые расширения из **Oberon-2** были адаптированы для **Active Oberon**:
 +
 +    ASSERT
 +    FOR
 +    экспорт только для чтения
 +    динамические массивы
 +
 +Переменные указатели автоматически инициализируются значением ''​NIL''​.
 +
 +
 +===== Список литературы =====
 +
 +[1]   A. Beugnard, J.-M. Jґezґequel,​ N. Plouzeau, and D. Watkins. Making components contract aware. Computer, 32(7):​38–45,​ July 1999.
 +
 +[2]   R. Brega. Real-time kernel for the Power-PC architecture. Master’s thesis, Institut fЁur Robotik, ETH ZЁurich, 1995.
 +
 +[3]   P. Brinch Hansen. Structured multiprogramming. Communications of the ACM, 15(7):​574–578,​ July 1972. Reprinted in The Search for Simplicity, IEEE Computer Society Press, 1996.
 +
 +[4]   ​Microsoft Corporation. Microsoft C# Language Specifications. Microsoft Press, 2001.
 +
 +[5]   ​Edsger W. Dijkstra. The structure of the THE-multiprogramming system. Communications of the ACM, 11(5):​341–346,​ May 1968.
 +
 +[6]   H. Eberle. Development and Analysis of a Workstation Computer. Dissertation 8431, ETH ZЁurich, 1987.
 +
 +[7]   P. FrЁohlich. Projekt Froderon: Zur weiteren Entwicklung der Programmiersprache Oberon-2. Master’s thesis, Fachhochschule MЁunchen, 1997.
 +
 +[8]   J. Gosling, B. Joy, and G. Steele. The Java Language Specification. The Java Series. Addison-Wesley,​ 1st edition, 1996.
 +
 +[9]   R. Griesemer. A Programming Language for Vector Computers. Dissertation 10277, ETH ZЁurich, 1993.
 +
 +[10]   J. Gutknecht. Do the fish really need remote control? A proposal for selfactive objects in Oberon. In Proc. of Joint Modular Languages Conference (JMLC). LNCS 1024, Linz, Austria, March 1997. Springer Verlag.
 +
 +[11]   J. Gutknecht and N. Wirth. Project Oberon - The Design of an Operating System and Compiler. Addison-Wesley,​ 1992.
 +
 +[12]   B. Heeb and C. Pfister. Chameleon: A workstation of a different colour. In Field-Programmable Gate Arrays: Architectures and Tools for Rapid Prototyping. Second International Workshop on Field Programmable Logic and Applications,​ pages 152–161, August 1992.
 +
 +[13]   C. A. R. Hoare. Monitors: An operating system structuring concept. Communications of the ACM, 17(10):​549–557,​ October 1974. Erratum in Communications of the ACM, Vol. 18, No. 2 (February), p. 95, 1975. This paper contains one of the first solutions to the Dining Philosophers problem.
 +
 +[14]   ​International Organization for Standardization. ISO/IEC 8652:1995: Information technology — Programming languages — Ada. International Organization for Standardization,​ Geneva, Switzerland,​ 1995.
 +
 +[15]   P. Januschke. Oberon-XSC - Eine Programmiersprache und Arithmetikbibliothek fЁur das Wissenschaftliche Rechnen. PhD thesis, UniversitЁat Karlsruhe, 1998.
 +
 +[16]   K. Jensen and N. Wirth. PASCAL - User Manual and Report, volume 18 of Lecture Notes in Computer Science. Springer, 1974.
 +
 +[17]   S. E. Knudsen. Medos-2: A Modula-2 oriented operating system for the personal computer Lilith. Diss no. 7346, ETH ZЁurich, 1983.
 +
 +[18]   B. Meyer. Object-Oriented Software Construction. Prentice Hall, 2nd edition, 1997.
 +
 +[19]   H. MЁossenbЁock,​ J. Templ, and R. Griesemer. Object Oberon: An objectoriented extension of Oberon. Technical Report 1989TR-109, Department of Computer Science, ETH ZЁurich, June 1989.
 +
 +[20]   H. MЁossenbЁock and N. Wirth. The programming language Oberon-2. Structured Programming,​ 12(4):​179–195,​ 1991.
 +
 +[21]   P.J. Muller. The Active Object System – Design and Multiprocessor Implementation. PhD thesis, ETH ZЁurich, 2002.
 +
 +[22]   R. Ohran. Lilith: A Workstation Computer for Modula-2. Dissertation 7646, ETH ZЁurich, 1984.
 +
 +[23]   A. Radenski. Introducing objects and concurrency to an imperative programming language. Information Sciences, an International Journal, 87(1- 3):​107–122,​ 1995.
 +
 +[24]   A. Radenski. Module embedding. Software - Concepts and Tools, 19(3):​122–129,​ 1998.
 +
 +[25]   B. A. Sanders and S. Lalis. Adding concurrency to the Oberon system. In Proceedings of Programming Languages and System Architectures,​ Lecture Notes in Computer Science (LNCS) 782. Springer Verlag, March 1994.
 +
 +[26]   C. Szyperski. Import is not inheritance – why we need both: modules and classes. In O. Lehrmann Madsen, editor, Proceedings,​ ECOOP 92, number 615 in Lecture Notes in Computer Science, pages 19–32. Springer-Verlag,​ 1992.
 +
 +[27]   ​Clemens Szyperski. Component Software: Beyond Object-Oriented Programming. ACM Press and Addison-Wesley,​ New York, NY, 1998.
 +
 +[28]   N. Wirth. MODULA : A language for modular multiprogramming. Software Practice and Experience, 7:3–35, 1977.
 +
 +[29]   N. Wirth. The programming language Oberon. Software Practice and Experience, 18(7):​671–690,​ July 1988.
 +
 +[30]   N. Wirth and M. Reiser. Programming in Oberon - Steps Beyond Pascal and Modula. Addison-Wesley,​ 1992.
 +
 +
 +===== A Синтаксис Active Oberon =====
 +
 +
 +<​code>​
 +Module ​    = MODULE ident ‘;’ [ImportList] {Definition} {DeclSeq} Body ident ‘.’.  ​
 +ImportList = IMPORT ident [‘:=’ ident] {‘,’ ident [‘:=’ ident ]} ‘;​’.  ​
 +Definition = DEFINITION ident [REFINES Qualident] {PROCEDURE ident [FormalPars] ‘;’} END ident.  ​
 +DeclSeq ​   = CONST {ConstDecl ‘;’} | TYPE {TypeDecl ‘;’} | VAR {VarDecl ‘;’} | {ProcDecl ‘;​’}.  ​
 +ConstDecl ​ = IdentDef ‘=’ ConstExpr.  ​
 +TypeDecl ​  = IdentDef ‘=’ Type.  ​
 +VarDecl ​   = IdentList ‘:’ Type.  ​
 +ProcDecl ​  = PROCEDURE ProcHead ‘;’ {DeclSeq} Body ident.  ​
 +ProcHead ​  = [SysFlag] [‘*’ | ‘&​’] IdentDef [FormalPars].  ​
 +SysFlag ​   = ‘[’ ident ‘]’.  ​
 +FormalPars = ‘(’ [FPSection {‘;’ FPSection}] ‘)’ [‘:’ Qualident].  ​
 +FPSection ​ = [VAR] ident {‘,’ ident} ‘:’ Type.  ​
 +Type       = Qualident  ​
 +           | ARRAY [SysFlag] [ConstExpr {‘,’ ConstExpr}] OF Type  ​
 +           | RECORD [SysFlag] [‘(’ Qualident ‘)’] [FieldList] END  ​
 +           | POINTER [SysFlag] TO Type  ​
 +           | OBJECT [[SysFlag] [‘(’ Qualident ‘)’] [IMPLEMENTS Qualident] {DeclSec} Body]  ​
 +           | PROCEDURE [SysFlag] [FormalPars].  ​
 +FieldDecl ​ = [IdentList ‘:’ Type].  ​
 +FieldList ​ = FieldDecl {‘;’ FieldDecl}.  ​
 +Body       = StatBlock | END.  ​
 +StatBlock ​ = BEGIN [‘{’IdentList‘}’] [StatSeq] END.  ​
 +StatSeq ​   = Statement {‘;’ Statement}.  ​
 +Statement ​ = [Designator ‘:=’ Expr  ​
 +           | Designator [‘(’ ExprList‘)’]  ​
 +           | IF Expr THEN StatSeq {ELSIF Expr THEN StatSeq}[ELSE StatSeq] END  ​
 +           | CASE Expr DO Case {‘|’ Case} [ELSE StatSeq] END  ​
 +           | WHILE Expr DO StatSeq END  ​
 +           | REPEAT StatSeq UNTIL Expr  ​
 +           | FOR ident ‘:=’ Expr TO Expr [BY ConstExpr] DO StatSeq END  ​
 +           | LOOP StatSeq END  ​
 +           | WITH Qualident ‘:’ Qualident DO StatSeq END  ​
 +           | EXIT  ​
 +           | RETURN [Expr]  ​
 +           | AWAIT ‘(’ Expr ‘)’  ​
 +           | StatBlock  ​
 +             ​].  ​
 +Case       = [CaseLabels { ‘,’ CaseLabels } ‘:’ StatSeq].  ​
 +CaseLabels = ConstExpr [‘..’ ConstExpr].  ​
 +ConstExpr ​ = Expr.  ​
 +Expr       = SimpleExpr [Relation SimpleExpr].  ​
 +SimpleExpr = Term {MulOp Term}.  ​
 +Term       = [‘+‘|’-’] Factor {AddOp Factor}.  ​
 +Factor ​    = Designator[‘(’ ExprList‘)’] | number | character | string  ​
 +           | NIL | Set | ‘(’Expr‘)‘|’ ’Factor.  ​
 +Set        = ‘{’ [Element {‘,’ Element}] ‘}’.  ​
 +Element ​   = Expr [‘..’ Expr].  ​
 +Relation ​  = ‘=’ | ‘#’ | ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | IN | IS.  ​
 +MulOp      = ‘*’ | DIV | MOD | ‘/’ | ‘&’ .  ​
 +AddOp      = ‘+’ | ‘-’ | OR .  ​
 +Designator = Qualident { ‘.’ ident | ‘[’ExprList‘]’ | ‘^’  ​
 +           | ‘(’ Qualident ‘)’ }.  ​
 +ExprList ​  = Expr {‘,’ Expr}.  ​
 +IdentList ​ = IdentDef {‘,’ IdentDef}.  ​
 +Qualident ​ = [ident ‘.’] ident.  ​
 +IdentDef ​  = ident [‘*‘|’-’].
 +</​code>​
 +
 +
 +
 +===== B Примеры синхронизации =====
 +
 +
 +==== B.1 Читатели и писатели ====
 +
 +<code oberon2>
 +MODULE ReaderWriter;  ​
 + 
 +TYPE  ​
 +  RW = OBJECT  ​
 +    (* n = 0, пусто *)  ​
 +    (* n < 0, n писателей *)  ​
 +    (* n > 0, n читателей *)  ​
 +    VAR n: LONGINT;  ​
 + 
 +    PROCEDURE EnterReader*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      AWAIT(n >= 0); INC(n)  ​
 +    END EnterReader;  ​
 + 
 +    PROCEDURE ExitReader*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      DEC(n)  ​
 +    END ExitReader;  ​
 + 
 +    PROCEDURE EnterWriter*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      AWAIT(n = 0); DEC(n)  ​
 +    END EnterWriter;  ​
 + 
 +    PROCEDURE ExitWriter*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      INC(n)  ​
 +    END ExitWriter;  ​
 + 
 +    PROCEDURE & Init;  ​
 +    BEGIN n := 0  ​
 +    END Init;  ​
 + 
 +  END RW;  ​
 + 
 +END ReaderWriter.
 +</​code>​
 +
 +Образец ''​Читатели --- Писатели''​ регулирует доступ к данным в //​критической секции//​. Либо один ''​Писатель''​ (активность,​ изменяющая состояние объекта),​ либо несколько ''​Читателей''​ (активности,​ не изменяющие состояние объекта) допускаются в критическую секцию в предоставленное время.
 +
 +==== B.2 Сигналы ====
 +
 +<code oberon2>
 +TYPE
 +  Signal* = OBJECT  ​
 +    VAR  ​
 +      in: LONGINT; (* следующий билет для выдачи *)  ​
 +      out: LONGINT; (* следующий билет для обслуживания *)  ​
 + 
 +    (* элементы с (out <= ticket < in) должны ждать *)  ​
 +    PROCEDURE Wait*;  ​
 +      VAR ticket: LONGINT;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      ticket := in; INC(in); AWAIT(ticket - out < 0)  ​
 +    END Wait;  ​
 + 
 +    PROCEDURE Notify*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      IF out # in THEN INC(out) END  ​
 +    END Notify;  ​
 + 
 +    PROCEDURE NotifyAll*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      out := in  ​
 +    END NotifyAll;  ​
 + 
 +    PROCEDURE & Init;  ​
 +    BEGIN in := 0; out := 0  ​
 +    END Init;  ​
 +  END Signal;
 +</​code>​
 +
 +''​Signal''​ реализует примитивы для работы с сигналами **Active Oberon** подобно тому, как это сделано в **Java** и **Modula-2**. Он использует слегка измененный ''​ticket-algorithm''​. Как в некоторых магазинах,​ каждый покупатель получает занумерованый билет, это //​гарантирует//,​ что покупатели будут обслужены в порядке их прибытия.
 +
 +==== B.3 Повторно входимые блокировки ====
 +
 +<code oberon2>
 +ReentrantLock* = OBJECT  ​
 +  VAR  ​
 +    lockedBy: PTR;  ​
 +    depth: LONGINT;  ​
 + 
 +  PROCEDURE Lock*;  ​
 +    VAR me: PTR;  ​
 +  BEGIN {EXCLUSIVE}  ​
 +    me := AosActive.CurrentThread();  ​
 +    AWAIT((lockedBy = NIL) OR (lockedBy = me));  ​
 +    lockedBy := me;  ​
 +    INC(depth)  ​
 +  END Lock;  ​
 + 
 +  PROCEDURE Unlock*;  ​
 +  BEGIN {EXCLUSIVE}  ​
 +    DEC(depth);  ​
 +    IF depth = 0 THEN lockedBy := NIL END  ​
 +  END Unlock;  ​
 +END ReentrantLock;​
 +</​code>​
 +
 +''​ReentrantLock''​ позволяет блокировать объект его хозяином //​более//​ одного раза. Клиенты этого объекта должны явно использовать ''​Lock''​ и ''​Unlock''​ вместо пометки защищаемого участка оператором ''​EXCLUSIVE''​.
 +
 +==== B.4 Бинарный и общий семафоры ====
 +
 +<code oberon2>
 +MODULE Semaphores;  ​
 + 
 +TYPE  ​
 +  Sem* = OBJECT (* Бинарный семафор *)  ​
 +    VAR taken: BOOLEAN  ​
 + 
 +    PROCEDURE P*; (* войти *)  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      AWAIT(~taken);​ taken := TRUE  ​
 +    END P;  ​
 + 
 +    PROCEDURE V*; (* войти *)  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      taken := FALSE  ​
 +    END V;  ​
 + 
 +    PROCEDURE & Init;  ​
 +    BEGIN taken := FALSE  ​
 +    END Init;  ​
 +  END Sem;  ​
 + 
 +  GSem* = OBJECT (* Общий семафор *)  ​
 +    VAR slots: LONGINT;  ​
 + 
 +    PROCEDURE P*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      AWAIT(slots > 0); DEC(slots)  ​
 +    END P;  ​
 + 
 +    PROCEDURE V*;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      INC(slots)  ​
 +    END V;  ​
 + 
 +    PROCEDURE & Init(n: LONGINT);  ​
 +    BEGIN slots := n  ​
 +    END Init;  ​
 +  END GSem;  ​
 +END Semaphores.
 +</​code>​
 +
 +Это хорошо известные синхронизирующие примитивы **Дейкстры** [5]. Заметим,​ что возможность реализовать семафоры показывает,​ что модель **Active Oberon** достаточно мощная для поддержки защиты и синхронизации параллельных процессов.
 +
 +==== B.5 Барьеры ====
 +
 +<code oberon2>
 +MODULE Barriers;  ​
 +(*  ​
 +  Барьер используется для синхронизации N активностей.  ​
 +*)  ​
 +TYPE  ​
 +  Barrier = OBJECT  ​
 +    VAR in, out, N: LONGINT;  ​
 + 
 +    PROCEDURE Enter*;  ​
 +      VAR i: LONGINT;  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      INC(in);  ​
 +      AWAIT (in >= N);  ​
 +      INC(out);  ​
 +      IF (out = N) THEN in := 0; out := 0 END;  ​
 +    END Enter;  ​
 + 
 +    PROCEDURE & Init (nofProcs: LONGINT);  ​
 +    BEGIN  ​
 +      N := nofProcs; in := 0; out := 0;  ​
 +    END Init;  ​
 +  END Barrier;  ​
 +END Barriers.
 +</​code>​
 +
 +Барьер используется для синхронизации активностей друг с другом. Если активности определены как
 +P = Phase ;P hase ;...P hase i i,0 i,1 i,n
 +
 +то барьер используется для гарантии того, что все активности выполнят ''​Phasei,​j''​ до начала ''​Phasei,​j+1''​. Отдельный поток исполнения будет выглядеть подобно следующему:​
 +<code oberon2>
 +  FOR j := 0 TO N DO  b
 +    Phase(i, j); barrier.Enter  ​
 +  END;
 +</​code>​
 +
 +Барьер сбрасывает счетчик ''​in''​ после выполнения условия чтобы избежать переполнения. Это возможно потому,​ что активности,​ повторно запрашивающие блокировку через инструкцию ''​AWAIT'',​ имеют более высокий приоритет по сравнению с активностями,​ запрашивающими блокировку в первый раз в том же блоке ''​EXCLUSIVE''​.
 +
 +==== B.6 Ограниченный буфер ====
 +
 +<code oberon2>
 +MODULE Buffers;  ​
 + 
 +CONST  ​
 +  BufLen = 256;  ​
 + 
 +TYPE  ​
 +  (* Buffer - FIFO буфер *)  ​
 +  Buffer* = OBJECT  ​
 +    VAR  ​
 +      data: ARRAY BufLen OF INTEGER;  ​
 +      in, out: LONGINT;  ​
 + 
 +    (* Put - вставить элемент в буфер *)  ​
 +    PROCEDURE Put* (i: INTEGER);  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      AWAIT ((in + 1) MOD BufLen # out); (*AWAIT ~полный *)  ​
 +      data[in] := i;  ​
 +      in := (in + 1) MOD BufLen  ​
 +    END Put;  ​
 + 
 +    (* Get - забрать элемент из буфера *)  ​
 +    PROCEDURE Get* (VAR i: INTEGER);  ​
 +    BEGIN {EXCLUSIVE}  ​
 +      AWAIT (in # out); (*AWAIT ~пустой *)  ​
 +      i := data[out];  ​
 +      out := (out + 1) MOD BufLen  ​
 +    END Get;  ​
 + 
 +    PROCEDURE & Init;  ​
 +    BEGIN  ​
 +      in := 0; out := 0;  ​
 +    END Init;  ​
 + 
 +  END Buffer;  ​
 + 
 +END Buffers.
 +</​code>​
 +
 +''​Buffer''​ реализует ограниченный кольцевой буфер. Методы ''​Put''​ и ''​Get''​ защищены от одновременного доступа;​ они так же проверяют наличие свободного места и данных соответственно,​ в противном случае активность приостанавливается до того, как место освободиться или поступят новые данные.
 +
 +===== C Примеры активных объектов =====
 +
 +
 +==== C.1 Обедающие философы ====
 +
 +<code oberon2>
 +MODULE Philo;  ​
 + 
 +IMPORT Semaphores;  ​
 + 
 +CONST  ​
 +  NofPhilo = 5; (* количество философов *)  ​
 + 
 +VAR  ​
 +  fork: ARRAY NofPhilo OF Semaphores.Sem;  ​
 +  i: LONGINT;  ​
 + 
 +TYPE  ​
 +  Philosopher = OBJECT  ​
 +    VAR  ​
 +      first, second: LONGINT;  ​
 + 
 +    (* вилки для философов *)  ​
 +    PROCEDURE & Init(id: LONGINT);  ​
 +    BEGIN  ​
 +      IF id # NofPhilo-1 THEN  ​
 +        first := id; second := (id+1)  ​
 +      ELSE  ​
 +        first := 0; second := NofPhilo-1  ​
 +      END  ​
 +    END Init;  ​
 + 
 +  BEGIN {ACTIVE}  ​
 +    LOOP  ​
 +      .... Думает....  ​
 +      fork[first].P;​ fork[second].P;  ​
 +      .... Ест ....  ​
 +      fork[first.V;​ fork[second].V  ​
 +    END  ​
 +  END Philosopher;  ​
 + 
 +VAR  ​
 +  philo: ARRAY NofPhilo OF Philosopher;  ​
 +BEGIN  ​
 +  FOR i := 0 TO NofPhilo DO  ​
 +    NEW(fork[i]);  ​
 +    NEW(philo[i]);  ​
 +  END;  ​
 +END Philo.</​code>​
 +
 +==== C.2 Решето Эратосфена ====
 +
 +<code oberon2>
 +MODULE Eratosthenes;​ (* prk 13.09.00 *)  ​
 + 
 +IMPORT Out, Buffers;  ​
 + 
 +CONST  ​
 +  N = 2000;  ​
 +  Terminate = -1; (* охранник *)  ​
 + 
 +TYPE  ​
 +  Sieve = OBJECT (Buffers.Buffer)  ​
 +    VAR prime, n: INTEGER; next: Sieve;  ​
 + 
 +    PROCEDURE & Init;  ​
 +    BEGIN  ​
 +      Init^; (* вызывает инициализатор Buffer (суперклас) *)  ​
 +      prime := 0; next := NIL  ​
 +    END Init;  ​
 + 
 +  BEGIN {ACTIVE}  ​
 +    LOOP  ​
 +    Get(n);  ​
 + 
 +    IF n = Terminate THEN  ​
 +      (* прервать выполнение *)  ​
 +      IF next # NIL THEN next.Put (n) END;  ​
 +        EXIT  ​
 +      ELSIF prime = 0 THEN  ​
 +        (* первое число всегда простое *)  ​
 +        Out.Int(n, 0); Out.String("​ простое"​);​ Out.Ln;  ​
 +        prime := n;  ​
 +        NEW (next)  ​
 +      ELSIF (n MOD prime) # 0 THEN  ​
 +        (* передать дальше,​ если это не множитель простого *)  ​
 +         ​next.Put (n)  ​
 +      END  ​
 +    END  ​
 +  END Sieve;  ​
 + 
 +  PROCEDURE Start*;  ​
 +    VAR s: Sieve; i: INTEGER;  ​
 +  BEGIN  ​
 +    NEW(s);  ​
 +    FOR i := 2 TO N-1 DO s.Put (i) END;  ​
 +    s.Put(Terminate) (* использовать охранника для индикации выполнения *)  ​
 +  END Start;  ​
 + 
 +END Eratosthenes.</​code>​
 +
 +''​Eratosthenes''​ использует //​отсеивающий алгоритм//​ для поиска простых чисел. Каждое решето --- это активный объект,​ который передает все полученные значения,​ не являющиеся множителем первого полученного числа, на следующее решето. Синхронизация осуществляется в буфере. ​
ao2004.txt · Последние изменения: 2019/11/08 19:54 — иван_денисов