Основы объектно-ориентированного проектирования

         

Сторожевой механизм


Как и предыдущий, следующий пример показывает применимость нашего механизма к задачам реального времени. Он также хорошо иллюстрирует понятие дуэли.

Мы хотим дать возможность некоторому объекту вызвать некоторую процедуру action при условии, что этот вызов будет прерван и булевскому атрибуту failed будет присвоено значение истина (true), если процедура не завершит свое выполнение через t секунд. Единственным доступным средством измерения времени является процедура wait (t), которая будет выполняться в течение t секунд.

Приведем решение, использующее дуэль. Класс, которому нужен указанный механизм, будет наследником класса поведения TIMED и предоставит эффективную версию процедуры action, отложенной в классе TIMED. Чтобы разрешить action выполняться не более t секунд, достаточно вызвать timed_action (t). Эта процедура запускает сторожа (экземпляр класса WATCHDOG), который выполняет wait (t), а затем прерывает клиента. Если же сама процедура action завершится в предписанное время, то сам клиент прервет сторожа. Отметим, что в приведенном классе у всех процедур с аргументом t: REAL имеется предусловие t>=0, опущенное для краткости.

deferred class TIMED inherit CONCURRENCY feature {NONE} failed: BOOLEAN; alarm: WATCHDOG timed_action (t: REAL) is -- Выполняет действие, но прерывается после t секунд, если не завершится -- Если прерывается до завершения, то устанавливает failed в true do set_alarm (t); unset_alarm (t); failed := False rescue if is_concurrency_interrupt then failed := True end end set_alarm (t: REAL) is -- Выдает сигнал тревоги для прерывания текущего объекта через t секунд do -- При необходимости создать сигнал тревоги: if alarm = Void then create alarm end yield; actual_set (alarm, t); retain end unset_alarm (t: REAL) is -- Удалить последний сигнал тревоги do demand; actual_unset (alarm); wait_turn end action is -- Действие, выполняемое под управлением сторожа deferred end feature {NONE} -- Реальный доступ к сторожу actual_set (a: WATCHDOG; t: REAL) is -- Запуск a для прерывания текущего объекта после t секунд do a.set (t) end ...Аналогичная процедура actual_unset предоставляется читателю...
feature {WATCHDOG} -- Операция прерывания stop is -- Пустое действие, чтобы позволить сторожу прервать вызов timed_action do -- Nothing end end separate class WATCHDOG feature {TIMED} set (caller: separate TIMED; t: REAL) is -- После t секунд прерывает caller; -- если до этого прерывается, то спокойно завершается require caller_exists: caller /= Void local interrupted: BOOLEAN do if not interrupted then wait (t); demand; callerl stop; wait_turn end rescue if is_concurrency_interrupt then interrupted:= True; retry end end unset is -- Удаляет сигнал тревоги (пустое действие, чтобы дать -- клиенту прервать set) do -- Nothing end feature {NONE} early_termination: BOOLEAN endЗа каждым использованием yield должно, как это здесь сделано, следовать retain в виде: yield; "Некоторый вызов"; retain. Аналогично каждое использование demand (или insist) должно иметь вид: demand; "Некоторый вызов "; wait_turn. Для принудительного выполнения этого правила можно использовать классы поведения.


Содержание раздела