Данные
Традиционный подход к разработке ПО встроенных систем подразумевает создание единой базы данных (централизованной или распределенной), к которой все процессы обращаются через специальные примитивы доступа. В общем случае обращение к некоторой структуре требует ее монополизации на момент обращения, что и неэффективно (несколько обращений к функциям ОС), и ненадежно (одна из самых частых и трудно обнаруживаемых ошибок возникает, когда программист забывает захватить ресурс или, что еще хуже, захватывает, но забывает освободить после использования). Проектирование единой базы данных обычно ведется только в интересах ПО без учета соответствия данных элементам реального оборудования. Это приводит к необходимости довольно сложной генерации данных ПО на основе исходной спецификации оборудования и сильно затрудняет задачу модификации данных в процессе функционирования системы ("на ходу").
Такие особенности встроенных систем, как структурное подобие большей части данных управляемому оборудованию и определенная локализация действий вокруг каждого устройства, прямо подталкивают к использованию объектно-ориентированной парадигмы, однако ее эффективность не очевидна.
Во-первых, не вызовет ли разбиение данных на сравнительно мелкие объекты (с точностью до прибора) значительного расходования памяти? Действительно, заголовки процессов в большинстве ОС достигают 100-200 байтов, поэтому представление объектов в виде полноправных процессов ОС действительно очень накладно. Но, как мы уже видели, возможны упрощенные синхронные варианты реализации объектов – при этом длина заголовка уменьшается на порядок.
Во-вторых, не подменяем ли мы сложные операции доступа к БД не менее дорогостоящими операциями обмена сообщениями? Другими словами, хорошо, если 90% запросов осуществляется к локальным данным объекта и только ради 10% приходится посылать сообщения, а если наоборот? Разумеется, на этот вопрос нет однозначного ответа, но практический опыт показывает, что обычно удается распределить данные по объектам достаточно удачно, т.е.
организовать своеобразный конвейер. Сначала управление получает один объект, который, пользуясь своими локальными данными, выполняет определенные действия и посылает сообщение следующему объекту с результатами своей работы в качестве параметра сообщения, т.е. сообщения играют не только информационную, но и управляющую роль.
Случаи, когда сообщение посылается только с целью получения данных, локализованных в другом объекте, нужно сводить к минимуму. Здесь также можно воспользоваться особенностями встроенных систем, в которых процессы чаще всего далеко не равноправны по приоритетам. Например, в телефонных станциях процессы установления/освобождения соединения критичны по времени, а процессы техобслуживания, которые по объему во много раз больше, — нет. Соответственно, при разбиении системы на объекты нужно учитывать только локализацию данных, необходимых для установления и разъединения соединений, а данные, которые требуются для техобслуживания, распределять, экономя только собственные силы.
В качестве примера рассмотрим упрощенную телефонную станцию.
Рис. 7.1. Упрощенная телефонная станция
АЛ – Абонентская Линия;
СЛ – Соединительная Линия;
ТК – Телефонная Книга;
КП – Коммутационное Поле.
Здесь каждому абоненту соответствует объект типа АЛ, каждой линии, соединяющей данную станцию с другой, — объект типа СЛ. Объект типа ТК является справочником номеров абонентов данной телефонной станции и хранит данные, необходимые для маршрутизации. Объект типа КП соответствует реальному коммутационному полю. Драйверы играют связующую роль с внешним миром и обычно реализуются в виде ассемблерных программ, вызываемых по прерываниям.
Когда абонент поднимает трубку, соответствующий объект АЛ получает сообщение, принимает все цифры номера и посылает сообщение объекту ТК с принятым номером в качестве параметра. Заметим, что все это время АЛ работает только со своими локальными данными. ТК осуществляет поиск вызываемого абонента также только по своим локальным данным и посылает сообщение найденному объекту типа АЛ или СЛ.Вызываемый абонент или соединительная линия по своим локальным данным определяет, занят он или свободен, и если свободен, то посылает сообщение КП на подключение. КП по своим локальным данным находит свободную промлинию и т.д.