Проектирование составных задач
Детальное проектирование составных задач, содержащих вложенные объекты. Синхронизация доступа к классам. Проектирование разъемов для межзадачных коммуникаций. Пример разъема для реализации буфера сообщений с ответом. Логика упорядочения событий.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | реферат |
Язык | русский |
Дата добавления | 06.03.2014 |
Размер файла | 2,9 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru/
Проектирование составных задач
Введение
После разбиения системы на задачи и проектирования скрывающих информацию классов следует приступать к детальному проектированию программы. На этом этапе разрабатывается внутреннее устройство составных задач, содержащих вложенные объекты, подробно рассматриваются вопросы синхронизации, создаются классы-разъемы, инкапсулирующие детали межзадачных коммуникаций, и определяется внутренняя логика упорядочения событий для каждой задачи. Для нескольких примеров, иллюстрирующих эти концепции, приводится реализация на псевдокоде.
Детальный проект подсистемы изображается на детальных диаграммах параллельной кооперации, которые конкретизируют диаграммы, разработанные на этапе разбиения на задачи. Здесь изображается внутреннее строение сгруппированных задач и объектов-разъемов.
1. Проектирование составных задач
проектирование задача синхронизация
Рассмотрим детальное проектирование составных задач, содержащих вложенные объекты. К ним относятся задачи, выявленные путем применения критериев группировки и инверсии. Обычно такие задачи проектируются в виде составных активных классов, включающих вложенные пассивные объекты.
Отношения между задачами и классами. Отношения между задачами и классами выстраиваются следующим образом. Активный объект - задача - запускается событием: внешним, внутренним или таймера. Затем он вызывает определенную операцию пассивного объекта. Пассивный объект бывает вложенным в задачу или внешним по отношению к ней. Эти два случая рассматриваются отдельно.
Класс, операции которого вызываются исключительно указанной задачей, может вкладываться в нее. Если же операции класса вызываются несколькими задачами, то класс должен оставаться внешним по отношению к каждой из них. В случае, когда обращения к классу осуществляются из разных задач, операции класса должны обеспечивать синхронизацию доступа к инкапсулированным данным.
Поскольку операции класса проектируются по-разному в зависимости от способа доступа к нему, важно четко определить контекст, в котором может использоваться класс. Эту информацию следует документировать в разделе «Предположения» спецификации класса.
Из соображений модульности и повторного использования кода иногда не стоит физически встраивать классы в задачу, даже если они только этой задачей и используются. Тем не менее в разделе «Предположения» следует отметить, что класс не обеспечивает внутренней синхронизации, и в каждый момент времени к нему может обращаться только одна задача.
Разделение обязанностей между задачами и классами. Иногда полезно разделить обязанности между задачей и вложенными в нее классами. Управление, упорядочение событий и коммуникации поручаются задаче, а все структурные детали оставляются на усмотрение скрывающего информацию класса.
Для взаимодействия с устройством ввода/вывода можно использовать асинхронную или периодическую задачу интерфейса, в которую вложен объект интерфейса устройства. Объект занимается чтением с физического устройства и записью на него, а задача отвечает за время и способ своей активизации, а также за метод взаимодействия с другими активными или пассивными объектами. Рассмотрим, как это работает в случае устройства ввода. Задача активизируется внешним событием или событием таймера, вызывает операцию пассивного объекта для считывания данных, а затем либо посылает сообщение задаче-потребителю, либо вызывает операцию объекта, абстрагирующего данные.
Объект интерфейса устройства, к которому обращается только одна задача, не обязан синхронизировать доступ к устройству. Но, если к устройству могут обращаться сразу несколько задач, объект придется перепроектировать. Вместо этого допустимо обеспечить последовательный доступ к объекту интерфейса устройства, введя задачу-монитор ресурса, которая будет принимать все запросы на ввод/вывод и вызывать операции объекта.
Другой пример - это разделение обязанностей между управляющей задачей и вложенным в нее объектом, зависящим от состояния. Объект инкапсулирует таблицу переходов состояний и хранит текущее состояние. Управляющая задача получает сообщения от нескольких задач-производителей, извлекает из них информацию о событии и передает ее зависящему от состояния объекту в виде входного параметра вызванной операции. Объект возвращает действие, которое надлежит выполнить, а задача инициирует выполнение указанного действия, посылая сообщение или вызывая операцию другого объекта.
В подобных случаях, когда обязанности разделяют между задачей и вложенным в нее объектом, обычно нет необходимости показывать на диаграмме внутреннюю структуру задачи - вместо этого описывается логика упорядочения событий. Но в более сложных ситуациях, когда имеется составная задача с несколькими вложенными объектами, наглядное изображение ее структуры может оказаться очень полезным.
Составная задача инкапсулирует вложенные в нее объекты. Такую задачу с несколькими вложенными объектами удобно изобразить на детальной диаграмме параллельной кооперации. Вся функциональность задачи обеспечивается содержащимися внутри нее объектами. У каждой составной задачи есть объект-координатор, который получает адресованные ей сообщения и вызывает операции других вложенных объектов. Примеры подобных задач будут приведены ниже.
Темпоральная группировка и объекты интерфейса устройств. Рассмотрим ввод/вывод с опросом с точки зрения разбиения на задачи и классы. Задача выделяется при помощи критерия периодической (если устройство одно) или темпоральной (если устройств несколько) группировки. Каждое пассивное устройство ввода/вывода инкапсулируется в класс интерфейса устройства. Необходимо определить операции, предоставляемые таким классом, и поместить класс внутрь задачи.
Рассмотрим теперь динамическое поведение. Задача активизируется событием таймера. Затем она вызывает операции каждого из объектов интерфейса, чтобы получить текущее состояние устройства.
Пример ввода/вывода с опросом приведен на рис.10.1. На диаграмме кооперации из аналитической модели представлены два объекта интерфейса устройства: Интерфейс Педали Тормоза и Интерфейс Двигателя (рис.10.la), которые следят за датчиками педали тормоза и двигателя соответственно. Датчики опрашиваются периодически с одной и той же частотой.
С точки зрения разбиения на задачи объекты Интерфейс Педали Тормоза и Интерфейс Двигателя объединяются в задачу Автодатчики на основе критерия темпоральной группировки. Задача Автодатчики (рис.10.1б) периодически активизируется событием таймера и читает показания датчиков. Если состояние какого-либо датчика изменилось, то посылается сообщение задаче Круиз-Контроль.
С точки зрения разбиения на классы создаются два разных класса интерфейса устройства для датчиков педали тормоза и двигателя (рис.10.1в). Каждый класс поддерживает две операции. Для датчика двигателя это операции читать (out состояниеДвигателя) и инициализировать, а для педали тормоза - читать (out состояниеТормоза) и инициали-зировать.
Если объединить названные подходы, то задачу Автодатчики нужно рассматривать как составную. Она содержит три объекта: координатор (Монитор Автодатчиков), а также объекты интерфейса устройств Интерфейс Педали Тормоза и Интерфейс Двигателя.
Рассмотрим динамическое поведение, изображенное на рис. 10.1г. Задача Автодатчики периодически активизируется событием таймера. В этот момент объект-координатор Монитор Автодатчиков считывает текущие значения датчиков, вызывая операции ИнтерфейсДвигателя.читать (out состояния Двигателя) и ИнтерфейсПедалиТормоза.читать (out состоянияТормоза). Если состояние какого-либо датчика изменилось, то задаче Круиз-Контроль посылается сообщение (или два сообщения), содержащее новые значения.
Поручив классу интерфейса устройства решать, как обращаться к устройству, а задаче - когда это делать, мы достигли большей гибкости решения и больших возможностей для повторного использования. Так, например, класс интерфейса устройства тормоза в разных приложениях мог бы использоваться асинхронными задачами ввода, периодическими задачами ввода или темпорально сгруппированными периодическими задачами ввода/вывода. Кроме того, в этот класс допустимо включить особенности различных датчиков педали тормоза, сохранив единый виртуальный интерфейс устройства.
Рис.1. Пример темпоральной группировки и объектов интерфейса устройств: а - аналитическая модель (классы интерфейса устройств); б - проектная модель (темпоральная группировка задач)
Рис. 2. Пример темпоральной группировки и объектов интерфейса устройств: в - проектная модель (темпоральная группировка задач); г - проектная модель (классы интерфейса устройств)
Группировка по управлению и объекты, скрывающие информацию. Рассмотрим группировку задач по управлению и объекты, скрывающие информацию. Управляющая задача активизируется асинхронно. Она вызывает операции одного или нескольких объектов.
На рис.10.2 приведен пример управляющей задачи и объектов, с которыми она взаимодействует. На диаграмме кооперации из аналитической модели (рис.10.2а) показано, что объект правление Банкоматом посылает сообщение, которое вызывает операции двух объектов (в зависимости от состояния): Интерфейс Устройства Печати Чеков и Интерфейс Устройства Выдачи Наличных.
Рис. 3. Пример задачи, сгруппированной по управлению, с пассивными объектами: а - аналитическая модель (диаграмма кооперации); б - задача, сгруппированная по управлению; в - классы, скрывающие информацию
С точки зрения разбиения на задачи зависящий от состояния управляющий объект Управление Банкоматом представляет собой управляющую задачу, так как исполняет диаграмму состояний строго последовательно. Такая задача выполняет в своем потоке управления и другие операции (зависящие от состояния действия) в соответствии с критерием группировки по управлению. На рис.10.26 изображена сгруппированная по управлению задача Контроллер Банкомата.
С точки зрения разбиения на классы (рис.10.2в) имеются три пассивных класса: зависящий от состояния класс Управление Банкоматом, который скрывает структуру и содержимое таблицы переходов состояний, и два класса интерфейса устройств вывода - Интерфейс Устройства Печати Чеков и Интерфейс Устройства Выдачи Наличных. Объект Управление Банко-матом предоставляет операцию обработать Событие, которая вызывается для обработки нового события и возвращает действие, подлежащее выполнению. Объект Интерфейс Устройства Печати Чеков предоставляет операцию напечатать Чек, а объект Интерфейс Устройства Выдачи Наличных - операцию выдать Наличные.
Рис. 4. Пример задачи, сгруппированной по управлению, с пассивными объектами: г - задача, сгруппированная по управлению, с вложенными пассивными объектами
Если объединить оба подхода (рис.10.2г), получится всего одна составная задача Контроллер Банкомата с координирующим объектом - Координатором Банкомата. Когда этой задаче приходит новый Запрос Управлению Банкоматом, его принимает Координатор Банкомата, который извлекает из запроса событие и вызывает операцию УправлениеБанкоматом. ОбработатьСобытие (in событие, out действие). Объект Управление Банкоматом просматривает таблицу переходов, принимая во внимание текущее состояние и новое событие. Найденный элемент таблицы содержит новое состояние и действие (или действия), которое надлежит выполнить. Затем Координатор Банкомата инициирует указанное действие. Если речь идет о выдаче наличных, то вызывается операция выдатьНаличные объекта Интерфейс Устройства Выдачи Наличных, которой в качестве входного параметра передается сумма, а в качестве выходного - результатВыдачи. Если же действие состоит в печати чека, то вызывается операция печататьЧек объекта Интерфейс Устройства Печати Чеков, которой в качестве входного параметра передается информацияЧека, а в качестве выходного - результатПечати.
2. Синхронизация доступа к классам
Если к классу может обращаться несколько задач, то его операции должны обеспечивать синхронизацию доступа к инкапсулируемым данным. Ниже описываются соответствующие механизмы: алгоритм взаимного исключения и алгоритм нескольких читателей и писателей.
Пример синхронизации доступа к классу. В качестве примера рассмотрим класс абстрагирования данных Хранилище Показаний Аналоговых Датчиков. При проектировании этого класса нужно принять решение о том, будет ли информация храниться в массиве или в связанном списке. Другое решение касается синхронизации: может ли к объекту такого класса осуществляться параллельный доступ и, если да, следует использовать алгоритм взаимного исключения или алгоритм читателей и писателей. Оба решения относятся только к проектированию класса, не затрагивая его пользователей.
Отделив вопрос о том, что делает класс (спецификация операций), от того, как это делается (проект класса), мы можем изолировать пользователей от модификаций внутреннего устройства класса. Допустимо следующее:
- трансформировать внутренние структуры данных, например применить связанный список вместо массива;
- заменить внутренний механизм синхронизации доступа к данным, в частности использовать алгоритм читателей и писателей вместо взаимного исключения.
Описанные изменения влияют только на внутреннее устройство класса: на внутренние структуры данных и внутренние операции, которые имеют доступ к этим структурам.
Операции класса абстрагирования данных. Сохранив внешний интерфейс класса Хранилище Показаний Аналоговых Датчиков, рассмотрим два разных метода синхронизации доступа к хранилищу:взаимное исключение и алгоритм читателей и писателей.
Наш класс предоставляет две операции (рис.3):
читатьАналоговыйДатчик (in идДатчика, out значениеДатчика,
out верхнийПредел, out нижнийПредел, out условиеТревоги)
Эта операция вызывается задачами-читателями, которые хотят получить показания датчиков из хранилища. Она возвращает значение датчика с заданным идентификатором, его верхний и нижний пределы, а также условие тревоги. Если значение попадает в диапазон между верхним и нижним пределом, то датчик функционирует нормально. Если же значение оказывается меньше нижнего или больше верхнего предела, то условие тревоги будет равно нижнему или верхнему пределу соответственно.
обновитьАналоговыйДатчик (in идДатчика, in значениеДатчика)
Данная операция вызывается задачами-писателями, которые хотят поместить в хранилище новое значение датчика, прочитанное из внешней среды. Операция проверяет, попало ли значение в безопасный диапазон, и, если это не так, устанавливает соответствующее значение условия Тревоги.
Рис. 5. Пример параллельного доступа к объекту абстрагирования данных
Синхронизация методом взаимного исключения. Сначала рассмотрим решение, основанное на взаимном исключении. В таком случае используется предоставляемый операционной системой двоичный семафор, у которого есть операции acquire (запросить) и release (освободить). Чтобы гарантировать взаимное исключение, каждая задача должна вызвать операцию acquire семафора readWriteSemaphore (изначально он установлен в единицу) перед тем, как пытаться получить доступ к хранилищу. Закончив работу с хранилищем, задача обращается к операции release. Вот псевдокод операций чтения и обновления:
class ХранилищеПоказанийАналоговыхДатчиков
private readWriteSemaphore : Semaphore := 1
public читатьАналоговыйДатчик (in идДатчика;,
out значениеДатчика, out верхнийПредел,
out нижнийПредел, out условиеТревоги)
-- Критическая секция операции чтения.
acquire (readWriteSemaphore) ;
значениеДатчика := хранилищеПоказаний
(идДатчика, значение);
верхнийПредел := хранилищеПоказаний
(идДатчика, верх);
нижнийПредел := хранилищеПоказаний
(идДатчика, низ);
условиеТревоги := хранилищеПоказаний
(идДатчика; тревога);
release(readWriteSemaphore);
end читатьАналоговыйДатчик;
При выполнении операции обновить надо не только записать в хранилище новое значение датчика, но и проверить условие тревоги:
public обновитьАналоговыйДатчик (in идДатчика,
in значениеДатчика)
-- Критическая секция операции записи.
acquire (readWriteSemaphore);
хранилищеПоказаний (идДатчика, значение) :=
значениеДатчика;
if значениеДатчика >= хранилищеПоказаний
АналоговыхДатчиков(идДатчика, верх)
then хранилищеПоказаний (идДатчика,
тревога) := верх;
elseif значениеДатчика<= хранилищеПоказа-
ний(идДатчика, низ)
then хранилищеПоказаний (идДатчика,
тревога) := низ;
else хранилищеПоказаний (идДатчика,
тревога) := норма;
end if;
release(readWriteSemaphore);
end обновитьАналоговыйДатчик;
Синхронизация нескольких читателей и писателей. Применение указанного метода позволяет нескольким читателям одновременно обращаться к хранилищу, но любой писатель получает монопольный доступ. Для этого применяются два двоичных семафора: readerSemaphore и readWriteSemaphore, инициализированных значением 1. Кроме того, хранится текущее число Читателей, первоначально равное нулю. Семафор readerSemaphore используется читателями, чтобы гарантировать взаимно исключающее обновление счетчика читателей. Семафор readWriteSemaphore задействован писателями для обеспечения взаимно исключающего доступа к хранилищу. Но к данному семафору обращаются также и читатели. Он захватывается первым читателем перед началом чтения из хранилища и освобождается последним читателем, закончившим чтение. Ниже приведен псевдокод операция чтения и обновления:
class ХранилищеПоказанийАналоговыхДатчиков
private числоЧитателей : Integer : = 0;
readerSemaphore :. Semaphore := 1;
readWriteSemaphore : Semaphore := 1;
public читатьАналоговыйДатчик (in идДатчика,
out значениеДатчика, out верхнийПредел,
out нижнийПредел, out условиеТревоги)
-- Операция чтения вызывается задачами-
-- читателями. Доступ к хранилищу разрешен
-- одновременно нескольким читателям
-- при условии, что нет ни одного писателя.
acquire (readerSemaphore) ;
Увеличить числоЧитателей;
if числоЧитателей = 1
then acquire (readWriteSemaphpre) ;
release (readerSemaphore) ;
значениеДатчика := хранилищеПоказаний
(идДатчика, значение);
верхнийПредел := хранилищеПоказаний
(идДатчика, верх);
нижнийПредел := хранилищеПоказаний
(идДатчика, низ);
условиеТревоги := хранилищеПоказаний
(идДатчика, тревога);
acquire (readerSemaphore) ;
Уменьшить числоЧитателей;
if числоЧитателей = 0
then release (readWriteSemaphore);
release(readerSemaphore);
end читатьАналоговыйДатчик;
Псевдокод операции обновления аналогичен написанному ранее для алгоритма взаимного исключения, поскольку писатели, желающие обновить хранилище, должны обеспечить взаимно исключающий доступ к нему:
public обновитьАналоговыйДатчик (in идДатчика,
in значениеДатчика)
-- Критическая секция операции записи.
acquire (readWriteSemaphore) ;
хранилищеПоказаний (идДатчика, значение) :=
значениеДатчика;
if значениеДатчика >= хранилищеПоказаний
(идДатчика, верх)
then хранилищеПоказаний (идДатчика,
тревога) := верх;
elseif значениеДатчика <=
хранилищеПоказаний (идДатчика,. низ)
then хранилищеПоказаний (идДатчика,
тревога) := низ;
else хранилищеПоказаний (идДатчика,
тревога) := норма;
end if;
release(readWriteSemaphore) ;
end обновитьАналоговыйДатчик;
Проблема решена, но код синхронизации оказался переплетенным с кодом доступа к хранилищу. Такие обязанности желательно развести, и в следующем разделе мы покажем, как это сделать.
Синхронизация нескольких читателей и писателей с помощью монитора. Ниже речь пойдет о применении мониторов для решения проблемы нескольких читателей и писателей. Напомним, что операции монитора выполняются в условиях взаимного исключения, поэтому представленное выше решение задачи о доступе к хранилищу показаний аналоговых датчиков методом взаимного исключения легко реализуется и с помощью мониторов. Однако к задаче посредством алгоритма читателей и писателей мониторы напрямую применяться не могут, так как операция читатьАналоговый Датчик должна одновременно выполняться несколькими читателями. Поэтому мы поступим иначе: инкапсулируем аспекты алгоритма читателей и писателей, касающиеся синхронизации, в монитор и перепроектируем класс Хранилище Показаний Аналоговых Датчиков. Приведем два решения. Первое реализует ту же функциональность, что и в предыдущем разделе, а второе обладает дополнительными функциями, предотвращающими ущемление писателей.
Объявим монитор ReadWrite, который использует два семафора и предоставляет четыре взаимно исключающие операции. Семафоры назовем reader Semaphore и readWriteSemaphore. Четыре вышеупомянутые операции - это startRead, endRead, startWrite и endWrite. Задача-читатель вызывает операцию startRead перед началом чтения и операцию endRead после его окончания. Задача-писатель вызывает операцию startWrite перед началом чтения и операцию endWrite после его окончания. Устройство монитора на базе семафоров описано в разделе 3.8.2. Такой монитор предоставляет для захвата ресурса операцию acquire, которая может приостановить задачу, если ресурс занят, а также операцию release для освобождения ресурса.
Операция startRead сначала должна захватить семафор readerSemaphore, увеличить число читателей и освободить семафор. Если счетчик читателей был равен нулю, то startRead должна захватить семафор readWriteSemaphore, который занимает первый читатель, а освобождает последний. Хотя операции монитора выполняются взаимно исключающим образом, семафор readerSemaphore все же нужен. Дело в том, что читатель может быть приостановлен в ожидании семафора readWriteSemaphore, в подобном случае он разблокирует монитор ReadWrite. Если другой читатель в этот момент захватит монитор, вызвав startRead или endRead, он будет ожидать семафора readerSemaphore. Ниже представлен проект монитора ReadWrite:
monitor ReadWrite
-- Предназначен для предоставления доступа к
-- ресурсам нескольким читателям и одному
-- писателю.
-- Объявляет целочисленный счетчик числа
-- читателей.
-- Объявляет семафор для доступа к счетчику
-- читателей.
-- Объявляет семафор для взаимно
-- исключающего доступа к буферу.
private числоЧитателей : Integer = 0;
readerSemaphore : Semaphore;
readWriteSemaphore : Semaphore;
public startRead ()
-- Читатель вызывает эту операцию перед
-- началом чтения.
readerSemaphore.acquire;
if числоЧитателей = 0
then readWriteSemaphore.acquire;
Увеличить числоЧитателей;
readerSemaphore.release;
end startRead;
public endRead ()
-- Читатель вызывает эту операцию после
-- окончания чтения.
readerSemaphore.acquire ;
Уменьшить числоЧитателей;
if числоЧитателей = 0
then readWriteSemaphore.release;
readerSemaphore.release;
end endRead;
public startWrite ()
--Писатель вызывает эту операцию перед
-- началом записи.
readWriteSemaphore.acquire;
end startWrite;
public endWrite ()
-- Писатель вызывает эту операцию после
-- окончания записи.
readWriteSemaphore.release;
end endWrite;
end ReadWrite;
Теперь перепроектируем класс Хранилище Показаний Аналоговых Датчиков так, чтобы он мог воспользоваться монитором ReadWrite. Для этого объявим в нем закрытый экземпляр монитора. Операция читатьАналоговыйДатчик теперь вызывает операцию монитора startRead перед началом чтения из хранилища и операцию endRead после его окончания. Операция обновитьАналоговыйДатчик вызывает операцию монитора startWrite перед началом записи в хранилище и операцию endWrite после ее окончания.
class ХранилищеПоказанийАналоговыхДатчиков
private multiReadSingleWrite : ReadWrite
public читатьАналоговыйДатчик (in идДатчика,
out значениеДатчика, out верхнийПредел,
out нижнийПредел, out условиеТревоги)
multiReadSingleWrite.startRead();
значениеДатчика : == хранилищеПоказаний
(идДатчика, значение);
верхнийПредел := хранилищеПоказаний
(идДатчика, верх);
нижнийПредел := хранилищеПоказаний
(идДатчика, низ);
условиеТревоги := хранилищеПоказаний
(идДатчика, тревога);
multiReadSingleWrite.endRead() ;
end читатьАналоговыйДатчик;
public обновитьАналоговыйДатчик (in идДатчика,
in значениеДатчика)
-- Критическая секция операции записи.
multiReadSingleWrite.startWrite() ;
хранилищеПоказаний (идДатчика, значение) :=
значениеДатчика;
if значениеДатчика >= хранилищеПоказаний
(идДатчика, верх)
then хранилищеПоказаний (идДатчика,
тревога) := верх;
elseif значениеДатчика <=
хранилищеПоказаний (идДатчика, низ)
then хранилищеПоказаний (идДатчика,
тревога) := низ;
else хранилищеПоказаний (идДатчика,
тревога) := норма;
end if;
multiReadSingleWrite.endWrite();
end обновитьАналоговыйДатчик;
end ХранилищеПоказанийАналоговыхДатчиков;
Синхронизация нескольких читателей и писателей без ущемления писателей. В предыдущем варианте решения есть одно неудобство. Если от читателей постоянно поступают запросы на чтение, писателю в течение неопределенно долгого времени может быть отказано в доступе к хранилищу. Этот феномен называется ущемлением писателя (writer starvation). Ниже показано решение проблемы путем введения дополнительного семафора writer Waiting. Операция startWrite теперь должна захватить семафор writerWaiting до захвата семафора readWrite Semaphore. Операция startRead захватывает (и освобождает) семафор writerWaiting перед тем, как захватить reader Semaphore.
Поясним, для чего нужны такие изменения. Предположим, что несколько читателей заняты чтением, а писатель в этот момент пытается обновить данные. Он успешно захватывает семафор writerWaiting, но дальше вынужден ждать, пока читатели освободят семафор readWriteSemaphore. Если приходит новый читатель, то он вызывает startRead и приостанавливается, ожидая освобождения семафора writerWaiting. Тем временем уже имеющиеся читатели заканчивают свои операции, и последний освобождает семафор readWriteSemaphore, который тут же переходит в распоряжение ожидающего писателя, а тот освобождает семафор writerWaiting, позволяя занять его читателю или писателю. В приведенном ниже псевдокоде реализации операций startRead и startWrite изменены:
monitor ReadWrite
-- Предотвращает ущемление писателей за счет
-- дополнительного семафора.
-- Предназначен для предоставления доступа к
-- ресурсам нескольким читателям и одному
-- писателю.
-- Объявляет целочисленный счетчик числа
-- читателей.
-- Объявляет семафор для доступа к счетчику
-- читателей.
-- Объявляет семафор для взаимно
-- исключающего доступа к буферу.
-- Объявляет семафор для ожидающих
-- писателей.
private числоЧитателей : Integer = 0;
readerSemaphore : Semaphore;
readWriteSemaphore: Semaphore;
writerWaitingSemaphore : Semaphore;
public startRead ()
-- Читатель вызывает эту операцию перед
-- началом чтения.
writerWaitingSemaphore.acquire;
writerWaitingSemaphore.release;
readerSemaphore.acquire;
if числоЧитателей = 0
then readWriteSemaphore.acquire;
Увеличить числоЧитателей;
readerSemaphore.release;
end startRead;
public endRead ()
-- Читатель вызывает эту операцию после
-- окончания чтения.
readerSemaphore.acqui.re;
Уменьшить числоЧитателей;
if числоЧитателей = 0
then readWriteSemaphore.release;
readerSemaphore.release;
end endRead;
public startWrite ()
-- Писатель вызывает эту операцию перед
-- началом записи.
writerWaitingSemaphore.acquire;
readWriteSemaphore.acquire;
writerWaitingSemaphore.release;
end startWrite;
public endWrite ()
-- Писатель вызывает эту операцию после
-- окончания записи.
readWriteSemaphore.release;
end endWrite;
end ReadWrite;
Класс Хранилище Показаний Аналоговых Датчиков может пользоваться всеми преимуществами нового решения, хотя мы не изменили в нем ни одной строчки.
3. Проектирование разъемов для межзадачных коммуникаций
Классы-разъемы инкапсулируют детали межзадачных коммуникаций, например сильно и слабо связанный обмен сообщениями. Сервисы для межзадачных коммуникаций и синхронизации может предоставлять многозадачное ядро. Подобные механизмы есть также в некоторых языках параллельного программирования, в частности Ada или Java. Но ни один из этих языков не поддерживает слабо связанный обмен сообщениями. Чтобы реализовать указанную возможность, необходимо спроектировать скрывающий информацию класс MessageQueue, инкапсулирующий очередь сообщений и предоставляющий операции для доступа к ней. Классы такого вида называются разъемами.
Ниже будут описаны три класса-разъема для реализации слабо связанного обмена сообщениями, сильно связанного обмена без ответа и сильно связанного обмена с ответом. Каждый разъем представляет собой монитор, одновременно обеспечивающий синхронизацию и скрывающий информацию о том, как это делается. В разъемах применяется синхронизация по условию. Такие мониторы могут использоваться как в однопроцессорной так и в многопроцессорной системе с разделяемой памятью.
Проектирование разъема, реализующего очередь сообщений. Разъем, реализующий очередь сообщений, используется для инкапсуляции механизма слабо связанного обмена сообщениями. Это монитор, инкапсулирующий очередь, которая обычно существует в виде связанного списка. Разъем предоставляет синхронизированные операции send для отправки сообщения (вызывается задачей-производителем) и receive для получения сообщения (вызывается задачей-получателем) - рис.10.4. Производитель приостанавливается, если очередь заполнена (messageCount = maxCount) и возобновляет работу, когда освобождается место для размещения нового сообщения. Поместив сообщение в очередь, производитель продолжает работать и в состоянии посылать новые сообщения. Потребитель приостанавливается, когда очередь пуста (messageCount = 0) и активизируется, как только в очередь поступит сообщение. Потребитель не приостанавливается, если в очереди есть сообщения. Предполагается, что может быть несколько производителей и один потребитель.
Рис. 6. Пример разъема для реализации очереди сообщений
monitor MessageQueue
-- Инкапсулирует очередь сообщений,
-- рассчитанную максимум на maxCount
-- сообщений. Операции монитора выполняются
-- взаимно исключающим образом.
private maxCount : Integer;
private messageCount : Integer = 0;
public send (in message)
while messageCount = maxCount do wait;
Поместить сообщение в очередь;
Увеличить messageCount;
if messageCount = 1 then signal;
end send;
public receive (out message)
while messageCount = 0 do wait;
Извлечь сообщение из очереди;
Уменьшить messageCount;
if messageCount = maxCount - 1 then signal;
end receive;
end MessageQueue;
Проектирование разъема, реализующего буфер сообщений. Разъем, реализующий буфер сообщений, используется для инкапсуляции механизма сильно связанного обмена сообщениями без ответа. Это монитор, инкапсулирующий буфер на одно сообщение. Разъем предоставляет синхронизированные операции для отправки и получения сообщений (рис. 10.5). Производитель вызывает операцию send, а потребитель - операцию receive. Производитель приостанавливается, если буфер заполнен. Поместив сообщение в буфер, производитель ждет, пока потребитель примет его. Потребитель приостанавливается, когда буфер пуст. Предполагается, что может быть несколько производителей и один потребитель.
monitor MessageBuffer
-- Инкапсулирует буфер сообщений, в котором
-- может находиться не более одного
-- сообщения. Операции монитора выполняются
-- взаимно исключающим образом.
private messageBufferFull : Boolean = false;
private messageCount : Integer = 0;
public send (in message)
Поместить сообщение в буфер;
messageBufferFull = true;
signal;
while messageBufferFull = true do wait;
end send;
public receive (out message)
while messageBufferFull = false do wait;
Извлечь сообщение из буфера;
messageBufferFull = false;
signal;
end receive;
end MessageBuffer;
Рис. 7. Пример разъема для реализации буфера сообщений
Проектирование разъема, реализующего буфер сообщений с ответом. Разъем, реализующий буфер сообщений с ответом, используется для инкапсуляции механизма сильно связанного обмена сообщениями с ответом. Это монитор, инкапсулирующий буфер на одно сообщение и буфер на один ответ. Разъем предоставляет синхронизированные операции для отправки и получения сообщений, а также для отправки ответа (рис.10.6). Производитель вызывает операцию send для пересылки сообщения, а потребитель - операцию receive для приема сообщения и операцию reply для отправки ответа. Поместив сообщение в буфер, производитель ждет ответа от потребителя. Потребитель приостанавливается, когда буфер пуст. Предполагается, что может быть несколько производителей и один потребитель.
monitor MessageBuffer&Response
-- Инкапсулирует буфер сообщений, в котором
-- может находиться не более одного
-- сообщения, и буфер, в котором может
-- находиться не более одного ответа.
-- Операции монитора выполняются взаимно
-- исключающим образом.
private messageBufferFull : Boolean = false;
private responseBufferFull : Boolean = false;
private messageCount : Integer = 0;
public send (in message)
Поместить сообщение в буфер;
messageBufferFull = true;
signal ;
while responseBufferFull = false do wait;
Извлечь ответ из буфера;
responseBufferFull = false;
end send;
public receive (out message)
while messageBufferFull = false do wait;
Извлечь сообщение из буфера;
messageBufferFull = false;
end receive;
public reply (in response)
Поместить ответ в буфер;
responseBufferFull = true;
signal ;
end reply;
end MessageBuffer&Response
Рис. 8. Пример разъема для реализации буфера сообщений с ответом
Проектирование кооперативных задач с использованием разъемов. Теперь рассмотрим проектирование группы кооперативных задач, общающихся между собой с помощью объектов-разъемов. Для иллюстрации воспользуемся примером из подсистемы Банкомат. Разъемы для этой подсистемы изображены на рис.10.7; есть два разъема - очереди сообщений и один разъем - буфер сообщений.
Рис. 9. Пример кооперативных задач, использующих разъемы
Объект Очередь Сообщений Управления Банкоматом инкапсулирует очередь входных сообщений задачи Контроллер Банкомата, для которой есть несколько производителей. Объект Очередь Сообщений Приглашений инкапсулирует очередь сообщений, посылаемых задачей Контроллер Банкомата задаче Интерфейс Клиента. И в том, и в другом случае производитель вызывает операцию send объекта-разъема, а потребитель - операцию receive того же объекта. Имеется также разъем буфер Сообщений Устройства Считывания, который инкапсулирует синхронный обмен без ответа между задачами Контроллер Банкомата и Интерфейс Устройства Считывания Карточек.
Наконец, есть объект заместитель Банковского Сервера. Он скрывает детали коммуникации с удаленным Банковским Сервером, применяя синхронный обмен сообщениями без ответа. Например, в языке Java этот заместитель воспользовался бы механизмом вызова удаленных методов (RMI), описанным ранее.
4. Логика упорядочения событий
На этапе детального проектирования ПО заполняется раздел «Логика упорядочения событий» в спецификации поведения задач. Ниже рассказывается, каким образом задача реагирует на входные сообщения или события и, в частности, какая при этом генерируется выходная информация. Логика упорядочения событий описывается неформально на псевдокоде или на естественном языке и иногда дополняется диаграммой. Например, для управляющей задачи может быть построена диаграмма перехода состояний.
В случае составной задачи с несколькими вложенными объектами входные сообщения принимает вложенный объект-координатор, который затем вызывает операции прочих объектов. Следовательно, он реализует логику упорядочения событий.
10.4.1. Пример логики упорядочения событий для задач отправителя и получателя. Ниже приводится логика упорядочения событий задачей-отправителем, которая посылает сообщения другим задачам. Конкретный вид операции send (сообщение) зависит от того, предоставляет сервис операционная система или используется объект-разъем.
loop
Подготовить сообщение, содержащее имя (тип)
и необязательные параметры;
Послать (сообщение) получателю;
endloop;
Логика упорядочения событий задачей-получателем такова:
loop
Принять (сообщение) от получателя;
Извлечь из сообщения имя и параметры;
case сообщение of
тип сообщения 1:
объектА.операциях (необязательные
параметры);
. . .
тип сообщения 2:
объектВ.операцияY (необязательные
параметры);
. . .
endcase ;
endloop;
Если применяется разъем aConnector, то операция отправки сообщения принимает вид
aConnector.send (сообщение)
а операция приема
aConnector.receive (сообщение)
Размещено на Allbest.ru
...Подобные документы
Инфологическое проектирование, анализ информационных задач и круга пользователей системы, определение требований к операционной обстановке. Объем внешней памяти занимаемый модулями СУБД и отводимой под данные. Логическое и физическое проектирование БД.
курсовая работа [314,9 K], добавлен 03.04.2010Проектирование базы данных Access. Система управления базами данных. Создание и обслуживание базы данных, обеспечение доступа к данным и их обработка. Постановка задач и целей, основных функций, выполняемых базой данных. Основные виды баз данных.
лабораторная работа [14,4 K], добавлен 16.11.2008Проектирование информационной системы бронирования билетов кассы аэропорта. Анализ информационных задач и круга пользователей системы. Составление реляционных отношений. Дополнительные ограничения целостности. Физическое проектирование базы данных.
курсовая работа [949,1 K], добавлен 28.03.2011Автоматизация расчетных задач проектирования. Создание трёхмерной модели офиса в виде целостной структуры здания. Расчёт потребления мощности электроэнергии офиса, проектирование схемы электроснабжения. Расположение необходимого оборудования в офисе.
курсовая работа [3,5 M], добавлен 23.11.2010Логическая и физическая схема действующей компьютерной сети. Проблемы, решение которых актуально для предприятия. Базы данных задач и работ бизнес-процессов. Структура информационной системы. Проектирование подсистемы "Управление основным производством".
курсовая работа [4,8 M], добавлен 17.12.2011Этапы проектирования базы данных. Инфологическое проектирование. Определение требований к операционной обстановке. Выбор СУБД и других программных средств. Логическое и физическое проектирование реляционной базы данных. Технология доступа к информации.
курсовая работа [2,3 M], добавлен 06.10.2016Анализ деятельности обменного пункта. Обоснование состава задач автоматического рабочего места. Проектирование иерархического меню, его содержание и структура. Разработка базы данных, экранных форм, отчетов. Программная реализация разработанной системы.
курсовая работа [529,2 K], добавлен 08.12.2013Пути создания функциональных подсистем. Структура системы и состав решаемых в подсистемах задач. Использование на каждом рабочем месте встроенных или локальных вычислительных средств с объединением их в локальную сеть. Особенности проектирования АСУ.
реферат [23,7 K], добавлен 06.11.2010Постановка задач автоматизированной системы управления "Автосервис". Описание технологий проектирования и инструментальных средствах. Проектирование структуры базы данных. Перечень функций в соответствии с функциональными блоками в диаграмме IDEFO.
дипломная работа [3,2 M], добавлен 06.03.2010Разработка информационной системы туристического агентства с использованием современных инструментальных средств, технологий; создание ее прототипа; определение целей, задач и функций ИС. Концептуальное, логическое и физическое проектирование базы данных.
курсовая работа [1,1 M], добавлен 09.06.2013Этапы разработки баз данных. Выделение сущностей с перечнем их атрибутов. Анализ информационных задач, круга пользователей системы. Логическое проектирование реляционных БД. Физическое проектирование. Реализация базы данных, направления данного процесса.
курсовая работа [434,8 K], добавлен 24.02.2012Проектирование базы данных для магазина продовольственных товаров. Предложения по модернизации информационных технологий. Выбор методов и средств решения задач, подлежащих автоматизации. Определение состава подсистем проектируемой информационной системы.
курсовая работа [3,9 M], добавлен 29.05.2013Жизненный цикл информационных систем, методологии и технологии их проектирования. Уровень целеполагания и задач организации, классификация информационных систем. Стандарты кодирования, ошибки программирования. Уровни тестирования информационных систем.
презентация [490,2 K], добавлен 29.01.2023Обследование предметной области. Концептуальное проектирование сущностей и атрибутов. Инфологическое проектирование базы данных, ее реляционная модель. Разработка представлений для отображения результатов выборки. Экономическое обоснование результатов.
курсовая работа [717,7 K], добавлен 23.06.2011Теоретические основы проектирования и разработки баз данных. Этапы физической реализации. Даталогическое и инфологическое проектирование. Определение сущностей, атрибутов, взаимосвязей между сущностями, ключей. Построение ER-модели. Управляющая программа.
курсовая работа [1,5 M], добавлен 02.06.2015Решение задач синтаксического анализа простой программы. Алгоритм нахождения синтаксических ошибок в ее тексте. Вывод данных о местоположении ошибки. Проектирование программы анализа арифметического выражения и методы проверки его на сумму или разность.
курсовая работа [2,6 M], добавлен 01.07.2011Создание автоматизированной информационной системы учета оборудования (компьютерной и оргтехники) на АКБ НМБ ОАО с использованием современных компьютерных средств. Проектирование базы данных. Алгоритмы решения задач. Расчёт затрат на проектирование.
дипломная работа [2,1 M], добавлен 16.12.2013Проектирование реляционной базы данных. Входная и выходная информация. Функциональные зависимости между атрибутами. Разработка представлений для отображения результатов выборки. Разработка механизмов управления данными в базе при помощи триггеров.
курсовая работа [1,6 M], добавлен 22.06.2011Возможности программы DBDesigner. Проектирование и реализация информационно-поисковой системы с помощью CASE-средства DBDesigner в среде Intranet. Этапы проектирования базы данных, установление соединения с базой данных на сервере, синхронизация.
лабораторная работа [1,5 M], добавлен 18.08.2009Декомпозиция автоматической системы управления на подсистемы и комплексы задач. Программное обеспечение комплекса задач подсистемы управления закупкой оборудования. Анализ существующей локальной вычислительной сети. Выбор дополнительных сетевых сервисов.
дипломная работа [4,0 M], добавлен 06.03.2013