|
|
|||||||||||||||||||||||||||||
На рис. 1 изображены три объекта, вызывающие метод send() из другого активного объекта. В этом случае первый объект, находящийся в состоянии готовности, может выдать вызов и выполнить метод. Если в это же время один или оба других объекта обращаются к send(), они становятся в очередь, связанную с методом, пока первый объект не закончит обработку вызова. Выполнение метода, принадлежащего активным объектам, неделимо и не пересекается с исполнением других методов того же самого объекта. Внутренняя активность активного объекта выносится наружу методом, вызываемым телом, которое исполняется в принадлежащем объекту потоке. Это тело имеет то же имя, что и класс, но с префиксом «@», что во многом аналогично конструктору/деструктору. Если тело выполняется, методы блокируются. Они могут выполняться только в том случае, если тело заканчивает работу или если тело приостанавливает работу по оператору accept, содержащему имя вызываемого метода.
Один оператор accept может принять только один метод. Но часто требуется обеспечить выполнение нескольких методов одновременно, как в следующем примере. 1 State1:
2 select {
3 obj1.send(msg);
4 printf(«sent !
»);
5 | |
6 accept recv;
7 printf(«received !
»);
8 | |
9 waituntil (now()+100);
10 printf(«time-out !
»);
11 goto State2
12 }Оператор select включает три случая, каждый из которых отделен двойной вертикальной чертой. Каждый случай начинается с оператора-триггера: либо вызывающего, либо принимающего часть рандеву или тайм-аута (строки 3, 6 и 9). Когда объект выполняет оператор select, он переходит в состояние ожидания, пока не появится одно из событий, определенных триггером. Первое же событие вызывает выполнение операторов, следующих за оператором-триггером, а затем программа выходит из оператора select. Этот оператор позднее должен быть выполнен повторно, если необходимо обработать и другие случаи.
Функция now() из строки 9 возвращает значение счетчика, расположенного в ядре и отсчитывающего сотые доли секунд. Определенное оператором waituntil событие наступает, если значение счетчика превысит величину, переданную как параметр waituntil, и если за это время не наступило никаких других событий, определенных в операторе select. Данный фрагмент программы соответствует автомату конечных состояний (Рис. 3). Наследование и виртуальные методыСинтаксис наследования классов активных объектов, называемых активными классами, и определения методов с отложенной готовностью идентичны пассивным классам других объектно-ориентированных языков. Тем не менее, смесь активных и пассивных классов является ограничивающим фактором — некоторые их комбинации могут привести к несовместимости. Наследование может обеспечить класс с различными интерфейсами, определенными его базовым классом и производными классами (созданными через подтипы). В языке sC++ каждый класс имеет дополнительное свойство активности (активный/пассивный) со следующими правилами наследования:
Действительно, было бы небезопасно позволять пассивному классу наследовать активный класс, поскольку вызывающий объект мог бы получить его в активной форме, если класс использует создание подтипов. С другой стороны, включение активных и пассивных объектов как членов класса — в обеих категориях класса — не создает никаких проблем, поскольку имена членов всегда отражают категорию их принадлежности к классу. В довершение всего, программист может переопределить методы пассивного класса, который был унаследован как личный активным классом в публичном режиме. Действуя подобным образом программист может использовать синтаксис, уже установленный для пассивных объектов, например: BaseClass::method. Это свойство может быть использовано для введения пассивных методов в активные объекты.
Наследование предохраняет тела активных базовых классов. Например, на рис. 4 показано, что каждый уровень класса имеет свое собственное независимое тело. Когда производный класс вызывает метод своего базового класса, производный класс синхронизируется, как и любой другой объект. Базовый класс должен принять метод, чтобы активизировать его выполнение. Когда внешний объект вызывает метод базового класса, создавая подтип, то для выполнения метода нужно принять только базовый класс, принятие производных классов не требуется.
Виртуальные методы, в терминах области видимости, встраивания и передачи параметров активных классов, определяются во многом подобно тому, как это делается в С++. Единственная разница в синхронизации: чтобы быть выполненным, виртуальный метод должен быть готов к работе во всех классах, в которых он был определен или переопределен. Другими словами, все другие методы (и тела) завершаются или находятся в состоянии приостановки на операторе, принимающем виртуальный метод. Таким образом, выполнение виртуального метода производит множественные рандеву между вызывающим объектом и всеми телами, которые принимают метод. В следующем примере активный класс определяет методы a(), b() и c() со свойством виртуальности. Тело принимает методы в следующем порядке: а() или b() принимаются первыми (строки с 9 по 13), затем с() (строка 14), затем опять а() или b() и так далее. На рис. 5 показано состояние конечного автомата на этом классе ActC1. 1 active class ActC1 {
2 public:
3 virtual void a() {printf («a
»); }
4 virtual void b() {}
5 virtual void c() {}
6 private:
7 @ActC1() {
8 for (;;) {
9 select {
10 accept a;
11 | |
12 accept b;
13 }
14 accept c;
15 }
16 }
17 };Благодаря ключевому слову virtual этот класс позволяет переопределить как свои действия, так и свои состояния. Например, следующий класс ActC1Deriv переопределяет методы b() и c() (строки 3 и 4), а также добавляет к их телам новые ограничения на то, как эти методы выполняются (строки с 9 по 15). Оба класса должны теперь одновременно принимать объект «b() соответственно с()», чтобы вычислить «b() соответственно с()».
1 active class ActC1Deriv:public ActC1 {
2 public:
3 void b() {} // redefinition
4 void c() {} // redefinition
5 void x() {} // new definition
6 private:
7 @ActC1Deriv () {
8 for (;;) {
9 select {
10 accept c;
11 | |
12 accept b;
13 accept x;
14 accept c;
15 }
16 }
17 }
18 };18.03.1999г Также в разделе:
|
Эта рубрика в архиве
Список номеров за
|
||||||||||||||||||||||||||||