WikiSort.ru - Программирование

ПОИСК ПО САЙТУ | о проекте
Active Oberon
Класс языка императивный, модульный, объектно-ориентированный, многопоточный, структурный, типобезопасный
Тип исполнения компилируемый, интерпретируемый
Появился в 1997 год
Автор Brinch Hansen, Юрг Гуткнехт (Jürg Gutknecht), Pieter Muller, Patrik Reali
Расширение файлов .Mod, mod
Система типов статическая, сильная
Основные реализации: Active Oberon.Net, FOX, PACO, Ronin
Диалекты Zonnon
Испытал влияние MATLAB, Модула-2, Оберон, Object Oberon, Паскаль
Повлиял на Active C#[1], Composita, Go, Zonnon
Платформа ARM, Cell, JVM, .NET, x86-32, x86-64
ОС A2, Darwin, Linux, Solaris, Windows
Сайт ocp.inf.ethz.ch/wiki/Doc…

Active Oberon — типобезопасный модульный объектно-ориентированный многопоточный язык программирования общего назначения, разработанный в 1996 — 1997 гг. группой проф. Гуткнехта[de] в Швейцарской высшей технической школе Цюриха (ETHZ) с целью введения в язык Оберон свойств для выражения параллелизма посредством активных объектов[2].

Особенности языка

Название Active Oberon отражает основную концепцию языка — концепцию Активных Объектов, выраженную в реализации многопоточности и механизмов синхронизации на уровне языка.

Active Oberon расширяет язык Оберон, вводя понятия Объект (Object) и Активность (Activity), связанная с Объектом. Такая связь называется Активным Объектом (Active Object), и означает способность экземпляра объекта иметь активность — собственный поток выполнения[2].

Язык относится к модульным типобезопасным языкам программирования с сильной статической типизацией, допуская в выражениях неявное приведение скалярных типов без потери данных (например, использование целого числа там, где предполагалось использование числа с плавающей точкой).

Модули обеспечивают не только раздельную компиляцию, инкапсуляцию, но и возможность реализации динамической загрузки/выгрузки скомпилированных (объектных) модулей, что используется, например, в операционной системе A2, написанной на этом языке. В некотором роде, аналогом модуля может считаться динамически подключаемая библиотека.

В Активном Обероне, как и в других наследниках Модулы-2, при обращении к сущностям подключенного (импортированного) модуля требуется обязательная квалификация подключенного модуля. Например, если модуль A подключает модуль B и использует переменную v этого модуля, то обращение к переменной должно иметь форму B.v. Иначе говоря, импорт в Активном Обероне не позволяет по умолчанию импортировать из подключенного модуля все экспортируемые им сущности.

Инкапсуляция построена на концепции модуля — все типы, объявленные в модуле, полностью прозрачны друг для друга, а для доступа внешних клиентов требуются спецификаторы доступа. Спецификаторы доступа позволяют экспортировать сущности либо с полным доступом (идентификатор помечается знаком «*»(звёздочка)), либо с доступом «только для чтения» (идентификатор помечается знаком «-» (минус)). Например, конструкция:

TYPE
  Example1* = RECORD x*, y-, z : LONGINT; END;

определяет тип записи (RECORD) Example1, экспортированный за пределы модуля и имеющий три поля с типом «длинное целое», причем поле «x» объявлено со спецификатором доступа «полный доступ», поле «y» объявлено со спецификатором «доступ только для чтения» и поле «z» является скрытым полем, недоступным внешним клиентам.

Язык поддерживает полиморфизм, перегрузку операций (для структурных типов), делегаты, совместимые как с методами, так и с процедурами. Объектными типами являются RECORD и ссылочный тип OBJECT. Они могут иметь методы и операции. У типа OBJECT могут быть тело и активность. Все методы являются виртуальными. Множественное наследование отсутствует, вместо него используется концепция множественного наследования интерфейсов (DEFINITION в терминах языка).

Синтаксис и семантика

Синтаксис языка в процессе развития практически не изменяется — разработчики предпочитают уточнять семантику уже имеющихся синтаксических конструкций с помощью вводимых семантических модификаторов, что позволяет исключить значительный объём правок при введении новой функциональности, упростить компилятор, сделав его код более доступным для понимания и модификации, а также обеспечить легкость изучения и использования языка. Модификаторы заключаются в фигурные скобки {} после имени переменной, типа или ключевого слова. Например, конструкция:

VAR
  Example2 : PROCEDURE {REALTIME, C} ( VAR low, high: LONGINT ): BOOLEAN;

объявляет процедурную переменную Example2, указывающую на процедуру реального времени, с соглашением о вызове CCALL, принимающую два параметра типа длинное целое и возвращающую значение логического типа.

Описание объекта, в целом, соответствует описанию модуля, за исключением синтаксиса заголовка и отсутствия секции IMPORT. Методы целиком описываются внутри описания объекта, операции, за редким исключением, могут описываться вне тела объекта. У объекта может быть произвольное количество инициализаторов и не более одного финализатора. Встроенная процедура NEW, использующаяся для создания переменных ссылочного типа, вызывает инициализатор, выбираемый компилятором по сигнатуре параметров. Инициализатор помечается знаком & перед именем метода. Финализатор — метод без параметров, перед именем которого стоит знак ~, — вызывается автоматически при утилизации объекта.

Последовательность операторов, заключенная в операторные скобки BEGIN END, называется блоком операторов. Блок операторов также может содержать список модификаторов и секцию гарантированного завершения (FINALLY).

Переменная, а также поле записи или объекта, могут быть инициализированы константным выражением при объявлении:

TYPE
    Point = RECORD
        x := 0,
        y := 0  : LONGINT;
    END;

VAR
    i := 0, j := 10, k := 100 : INTEGER;
    Point : Point; (* поля x, y записи инициализированы значением 0 *)

Типы данных

Язык предлагает богатый набор встроенных типов:

  • Базовые типы
    • логический: BOOLEAN;
    • символьные: CHAR8, CHAR16, CHAR32 и псевдоним CHAR для символьного типа по умолчанию;
    • целочисленные знаковые: SIGNED8, SIGNED16, SIGNED32, SIGNED64 и псевдонимы SMALLINT, INTEGER, LONGINT, HUGEINT;
    • целочисленные беззнаковые: UNSIGNED8, UNSIGNED16, UNSIGNED32, UNSIGNED64;
    • вещественные: REAL, LONGREAL;
    • комплексные: COMPLEX, LONGCOMPLEX;
    • машинозависимые: SIZE, ADDRESS;
    • множество: SET, SET8, SET16, SET32, SET64;
    • расширяемые перечисления: ENUM;
  • структурные
    • массивы: ARRAY — статические, динамические, открытые, математические;
    • расширяемые структуры: RECORD;
    • объектные: OBJECT;
  • Специальные
    • процедурные;
    • делегаты: процедурные переменные, совместимые как с процедурами, так и с методами;
    • типизированные указатели на структурные типы;
    • обобщенные указатели: ANY, OBJECT, ARRAY;
  • системные: SYSTEM.BYTE

Многопоточность

Для Активного Оберона реализовано две модели многопоточности, основанные на работах Бринча Хансена и Тони Хоара[3]:

Исходный код, написанный с использованием синтаксиса блокирующих примитивов синхронизации языка Active Oberon, может использоваться для обеих моделей многопоточности — компилятор будет генерировать нужный для конкретной модели код. При таком подходе нет нужды в переписывании программного обеспечения под разные модели. Лишь небольшие участки исходного кода требуют адаптации (например, обработка прерываний), чтобы подавить автоматическую генерацию переключений в данном участке машинного кода. Для этого блок операторов помечается модификатором {UNCOOPERATIVE}.

Активные Объекты

Поток инкапсулирован в объекте и, являясь его неотъемлемой частью, создаётся в момент инстанцирования активного объекта. Для указания активности объекта его тело помечается модификатором ACTIVE.

После размещения экземпляра объекта выполняется инициализатор (если есть), затем тело объекта (если есть). Если объект помечен как активный, создается активность, в которой асинхронно выполняется тело объекта, в противном случае выполнение производится синхронно в том потоке, в котором был создан экземпляр.

Активность объекта завершается после завершения исполнения тела объекта. Пока исполняется тело, объект продолжает существовать, даже если на него нет ссылок. После этого объект становится пассивным и может быть утилизирован в соответствии с обычными правилами.

Пример описания и использования активного объекта:

 1 MODULE Example3;
 2 
 3 TYPE
 4   ActiveObject = OBJECT
 5   VAR state : SET;
 6 
 7     PROCEDURE &New;
 8     BEGIN
 9       state := {};
10     END New;
11 
12     PROCEDURE &Init*( state : SET );
13     BEGIN
14       SELF.state := state;
15     END Init;
16 
17     PROCEDURE ~Finalize;
18     BEGIN
19     ...
20     END Finalize;
21 
22   BEGIN {ACTIVE}
23     ...
24   END ActiveObject;
25 
26 VAR
27   object : ActiveObject;
28 
29 BEGIN
30   NEW( object );
31   object.Init( {0..7, 9, 12, 30..31} );
32   NEW( object, {} );
33 END Example3.

Межпроцессное взаимодействие

Вызовы методов совместно используемых активных и неактивных объектов действуют как коммуникационный механизм между активными объектами. Поскольку активные объекты существуют в многопоточной среде, предоставляется механизм для координирования параллельного доступа к их состоянию. Взаимодействие посредством обмена сообщениями может осуществляться с использованием специальных программных каркасов.[5]

Защита от одновременного выполнения

Блок операторов, помеченный модификатором EXCLUSIVE называется монопольной областью (exclusive region). Монопольная область в Активном Обероне, соответствует концепции критической области Хансена[6]. Если монопольная область охватывает всё тело метода, то он называется монопольным методом (exclusive method) и совмещает концепцию Хансена с процедурой монитора Хоара[7][8]. В отличие от процедуры монитора, метод объекта не обязан быть монопольным — в этом случае он может наблюдать несогласованные состояния объекта. В монопольной области может находиться не более одной активности одновременно.

Таким образом, модель защиты в Активном Обероне — монитор, размещенный в экземпляре объекта (instance-based monitor). Модуль считается объектным типом с единственным экземпляром (singleton instance) и его процедуры тоже могут быть монопольными, защищая модуль в целом.

Главная идея монитора (и активного объекта) в том, что с монитором связывается некий инвариант — выражение, определяющее непротиворечивое внутреннее состояние объекта и доказывающее правильность его поведения[9]. Инициализаторы и монопольные методы являются инструментами, предоставляемыми языком, для поддержания инвариантов объекта и сокрытия его внутреннего состояния. Инициализатор объекта устанавливает его инвариант, а монопольные методы его поддерживают. Когда понятие монитора объединено с понятием модуля, формируется мощный механизм для структурирования операционных систем[10][11][12].

Пример использования монопольной секции:

 1 (* Процедуры Set и Reset взаимно исключаемы *)
 2 TYPE
 3   MyContainer = OBJECT
 4     VAR x, y: LONGINT; (* Инвариант: y = f(x) *)
 5 
 6     PROCEDURE Set(x: LONGINT);
 7     BEGIN {EXCLUSIVE} (* изменение x и y атомарно *)
 8       SELF.x := x; y := f(x)
 9     END Set;
10 
11     PROCEDURE Reset;
12     BEGIN
13       ...
14       BEGIN {EXCLUSIVE} (* изменение x и y атомарно *)
15         x := x0; y := y0;
16       END;
17       ....
18     END Reset;
19   END MyContainer;

Синхронизация

В отличие от большинства реализаций мониторов, использующих для синхронизации условные переменные Хоара[8] (на основе очередей событий Бринча Хансена[6]), синхронизацию активностей обеспечивает оператор AWAIT, принимающий в качестве аргумента логическое выражение — условие продолжения выполнения программы в теле объекта. Чтобы гарантировать правильность синхронизации, AWAIT должен находиться в монопольной области. В случае невыполнения условия продолжения, AWAIT приостанавливает (suspend) активность и, если находится в монопольной области, отпускает захваченную область на время приостановки, что позволяет другим активностям изменить состояние объекта и сделать условие продолжения истинным. Приостановленная активность продолжит работу только в том случае, если сможет повторно войти в монопольную область.

Пример синхронизации внутри разделяемого буфера:

 1 TYPE
 2   Synchronizer = OBJECT
 3     VAR awake: BOOLEAN
 4 
 5     PROCEDURE Wait;
 6     BEGIN {EXCLUSIVE}
 7       AWAIT(awake);
 8       awake := FALSE;
 9     END Wait;
10 
11     PROCEDURE WakeUp;
12     BEGIN {EXCLUSIVE}
13       awake := TRUE;
14     END WakeUp;
15   END Synchronizer;

Обработка ошибок и исключительных ситуаций

В Активном Обероне отсутствуют средства структурной обработки исключительных ситуаций — они обрабатываются централизовано средой времени выполнения.

Оператор ASSERT принимает в качестве обязательного аргумента логическое выражение, в случае нарушения которого происходит прерывание программы и, также, как и при выполнении оператора безусловного останова HALT, управление передаётся в централизованный обработчик исключений. Если условие оператора ASSERT может быть вычислено на этапе компиляции, то, в случае невыполнения условия генерируется ошибка компиляции. Оператор ASSERT и HALT могут иметь необязательный параметр — спецификатор исключения, который может быть проанализирован обработчиком.

После обработки исключения управление передаётся в ближайшую по стеку вызовов секцию гарантированного завершения FINALLY, если она есть. Затем, если тело активного объекта помечено модификатором SAFE, будет произведён перезапуск активности, в противном случае работа активности завершается.

Среда времени выполнения

Информация о типах времени выполнения

Только структурные типы (массивы, записи, объекты) имеют информацию о типах времени выполнения (метаинформацию). Метаинформация хранится в специальной структуре, называемой Дескриптор типа. Дескриптор типа содержит данные о типах и именах переменных и полей, таблицу наследования, таблицу виртуальных методов и таблицы реализованных интерфейсов.

Управление памятью

В Активном Обероне применяется автоматическое управление памятью с использованием прерываемого (вытесняемого) сборщика мусора реального времени[13], основанного на методе пометок (Mark and Sweep). Сборщик мусора выполняется в отдельном потоке, и активности (потоки), имеющие приоритет выше, чем приоритет активности сборщика мусора, могут приостановить его выполнение. При этом дерево объектов замораживается. На текущий момент только сущности реального времени могут прерывать активность сборщика мусора, в них запрещено динамическое выделение памяти, за этим следит компилятор.

Управление памятью основано на использовании типизированных участков памяти. Такой участок хранит указатель на дескриптор типа. Используя информацию о типах времени выполнения, находящуюся в дескрипторе типа, сборщик мусора находит переменные и поля ссылочного типа и помечает блоки, на которые они указывают. Другими словами, сборщику мусора нет необходимости проверять каждое значение, похожее на указатель, является ли оно корректным указателем в куче — используя информацию, предоставляемую дескриптором типа, он точно знает, какие элементы обрабатывать, что существенно увеличивает скорость и точность работы и снижает нагрузку на процесс сборки мусора. Для ускорения выделения памяти свободные участки помещаются в Списки свободных блоков, содержащие блоки памяти определенных размеров.

Переменные ссылочного типа, помеченные модификатором UNTRACED относятся к нетрассируемым указателям. Такие указатели не отслеживаются сборщиком мусора и участки памяти, на которые они ссылаются, могут быть утилизированы в любой момент времени, в случае, если они были выделены средой времени выполнения и на них нет достижимых ссылок, учитываемых сборщиком мусора. Часто, такие модификаторы используются для работы с участками памяти, выделенными вне среды времени выполнения Активного Оберона, или с небезопасными указателями.

Управление активностью объектов

Среда времени выполнения отвечает за распределение процессорного времени, гарантирует (совместно с компилятором), что в монопольной области находится не более одной активности, обеспечивает своевременную проверку условий оператора AWAIT и возобновление работы приостановленных активностей. Выражения условий продолжения внутри объекта пересчитываются во всех точках выхода из монопольных областей. Это означает, что изменение состояния объекта вне монопольной области не приводит к пересчёту условий. Когда несколько активностей соревнуются за одну и ту же монопольную область, то активности с выполненными условиями рассматриваются раньше тех, которые только хотят войти в защищенную область[3][14].

Подключение и инициализация модулей

В Активном Обероне отсутствуют средства для прямого управления динамической загрузкой и выгрузкой модулей. Язык предлагает лишь секцию импорта (IMPORT), в которой указан список подключаемых модулей и секцию инициализации модуля. Среда времени выполнения должна обеспечить подключение и инициализацию подключаемых модулей до инициализации текущего модуля. Динамическое подключение модуля осуществляется через механизм динамического связывания. Модуль нельзя выгрузить до тех пор, пока на него есть ссылка из списка подключения другого загруженного модуля. Таким образом, чтобы исключить проблему циклических ссылок, модули должны выгружаться в порядке, обратном порядку загрузки.

Обработка ошибок и исключительных ситуаций

Модуль Traps обеспечивает централизованную обработку исключительных ситуаций. Параметры, принимаемые операторами ASSERT и HALT, могут использоваться для классификации исключительной ситуации.

В текущей реализации, если процедура, в которой произошла исключительная ситуация, содержит логическую переменную trap, то значение переменной будет установлено в TRUE, что в дальнейшем может использоваться для анализа в секции FINALLY. После обработки исключительной ситуации в модуле Traps, среда времени выполнения осуществляет поиск секций гарантированного завершения FINALLY и передает на них управление для выполнения завершающих операций. В случае, если активность помечена модификатором SAFE, производится перезапуск активности.

Программный интерфейс среды выполнения предоставляет возможность установки собственного обработчика исключительных ситуаций.

Расширения языка

Active Cells

Math Oberon

Примеры программ

Hello, World!

1 MODULE HelloWorld;
2 IMPORT KernelLog;
3 
4 BEGIN
5   KernelLog.String( "Hello, World!" );
6 END HelloWorld.

Решение классической задачи поставщика и потребителя

 1 MODULE BoundedBuffers;
 2 TYPE
 3   Item* = OBJECT;
 4 
 5   Buffer* = OBJECT
 6     VAR
 7       h, n: INTEGER;
 8       B: ARRAY * OF Item;
 9 
10     PROCEDURE Get*(): Item;
11     VAR x: Item;
12     BEGIN {EXCLUSIVE}
13       AWAIT(n # 0); (* буфер не пуст *)
14       x := B[h]; h := (h+1) MOD LEN(B); DEC(n);
15       RETURN x
16     END Get;
17 
18     PROCEDURE Put*(x: Item);
19     BEGIN {EXCLUSIVE}
20       AWAIT(n # LEN(B)); (* буфер не полон *)
21       B[(h+n) MOD LEN(B)] := x; INC(n)
22     END Put;
23 
24     PROCEDURE &Init(max: INTEGER);
25     BEGIN (* инициализатор *)
26       NEW(B, max); h := 0; n := 0
27     END Init;
28   END Buffer;
29 
30 END BoundedBuffers.

Ссылки


См. также

Примечания

  1. Страница проекта Active C# Архивировано 4 сентября 2011 года.
  2. 1 2 J. Gutknecht. Do the Fish Really Need Remote Control? A Proposal for Self-Active Objects in Oberon., 1997.
  3. 1 2 3 P.J. Muller. Active Object System. Design and Multiprocessor Implementation. — ETH Zurich, 2002., Diss. ETH № 14755.
  4. Florian Negele. Combining Lock-Free Programming with Cooperative Multitasking for a Portable Multiprocessor Runtime System, ETH Zurich, 2014, Diss. ETH №. 22298
  5. Florian Negele. A2 Concurrency Framework, ETH Zurich, June 3, 2009
  6. 1 2 P. Brinch Hansen. Structured Multiprogramming. Communications of the ACM, 15(7), July 1972
  7. P. Brinch Hansen. Operating System Principles. Prentice-Hall, 1973.
  8. 1 2 C.A.R. Hoare. Monitors: An Operating System Structuring Concept. Communications of the ACM, 17(10):549-557, October 1974.
  9. O. J. Dahl. Monitors Revisited. In A.W. Roscoe, editor, A Classical Mind — Essays in Honour of C.A.R. Hoare. Prentice-Hall,
    1994.
  10. J.L. Keedy. On Structuring Operating Systems With Monitors. ACM Operating Systems Review, 13(1), January 1979.
  11. N. Wirth. Modula: A Language for Modular Multiprogramming. Software — Practice and Experience, 7:3-35, 1977.
  12. N. Wirth. The Use of Modula. Software — Practice and Experience, 7:37-65, 1977.
  13. Ulrike Glavitsch. Real-time Garbage Collection in A2. Institute of Computer Systems, ETH Zurich
  14. P. Reali. Active Oberon Language Report. — ETH Zurich, 2004.

Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".

Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.

Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .




Текст в блоке "Читать" взят с сайта "Википедия" и доступен по лицензии Creative Commons Attribution-ShareAlike; в отдельных случаях могут действовать дополнительные условия.

Другой контент может иметь иную лицензию. Перед использованием материалов сайта WikiSort.ru внимательно изучите правила лицензирования конкретных элементов наполнения сайта.

2019-2024
WikiSort.ru - проект по пересортировке и дополнению контента Википедии