Инструментальный компьютер Целевая система

 

Рисунок 3. Аппаратно-программный комплекс программирования-отладки систем на базе ОСРВ VxWorks и интегрированной среды Tornado

 

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

Для поддержки программирования предлагается интегрированная среда раз­работки Tornado, в состав которой входит VxWorks 5.3 - ядро РВ и системные биб­лиотеки, средства программирования C/C++ Toolkit, высокоуровневый отладчик CrossWind и ряд других средств. Пакет C/C++ Toolkit содержит компиляторы GNU C/C++ фирмы Cygnus Support. Отладчик CrossWind является расширенной версией отладчика GDB фирмы Cygnus Support. Он имеет графический пользовательский интерфейс и поддерживает отладку как на прикладном, так и на системном уровне. Дополнительные средства среды Tornado обеспечивают управление процессом от­ладки, визуализацию состояния целевой системы, другие сервисные функции.

Tornado может использоваться совместно с VX-Windows, WindView, Stetho­Scope, VxSim и рядом других средств из состава VxWorks.

Характерной особенностью среды Tornado является ее открытая архитектура, которая позволяет пользователю подключать собственные специализированные ин­струментальные средства и расширять возможности стандартных. Открытость реа­лизована с помощью прикладных программных интерфейсов API, которые дают возможность различным программным продуктам обмениваться между собой дан­ными на инструментальном компьютере и взаимодействовать с VxWorks, установ­ленной на целевой системе.

ОСРВ VxWorks вместе с интегрированной средой Tornado является мощным средством реализации целевых систем, работающих в условиях жестких ограниче­ний на объем используемой памяти и время отклика на внешние события. Подроб­ную информацию по VxWorks и сопутствующим программным продуктам можно получить в сети Интернет по адресу http:/www. wrs.com.


Лекция 3.7. Сетевая операционная система реального времени QNX

1. Принципы построения СРВ QNX.

2. Архитектура системы QNX.

3. Основные механизмы QNX для организации распределенных вычисле­ний.

 

1. Принципы построения СРВ QNX

Операционная система QNX является мощной операционной системой, по­зволяющей проектировать сложные программные системы, работающие в реаль­ном времени как на одном компьютере, так и в локальной вычислительной сети. Встроенные средства операционной системы QNX обеспечивают поддержку мно­гозадачного режима на одном компьютере и взаимодействие параллельно выпол­няемых задач на разных компьютерах, работающих в среде локальной вычисли­тельной сети. Основным языком программирования в системе является язык С. Основная операционная среда соответствует стандартам POSIX-интерфейса. Это позволяет с небольшими доработками перенести необходимое накопленное про­граммное обеспечение в среду операционной системы QNX для организации их работы в среде распределенной обработки.

ОС QNX является сетевой, мультизадачной, многопользовательской (мно­готерминальной) и масштабируемой. С точки зрения пользовательского интер­фейса и API она похожа на UNIX. Однако QNX - это не версия UNIX. QNX была разработана канадской фирмой QNX Software Systems Limited в 1989 году по за­казу Министерства обороны США. Причем эта система построена на совершенно других архитектурных принципах, отличных от принципов, использованных при создании ОС UNIX.

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

Предсказуемость, означающая ее применимость к задачам жесткого реаль­ного времени. QNX является операционной системой, которая дает полную гаран­тию в том, что процесс с наивысшим приоритетом начнет выполняться практиче­ски немедленно, и что критическое событие (например, сигнал тревоги) никогда не будет потеряно. Ни одна версия UNIX не может достичь подобного качества, поскольку код ядра слишком велик. Любой системный вызов из обработчика пре­рывания в UNIX может привести к непредсказуемой задержке (то же самое каса­ется Windows NT).

Масштабируемость и эффективность, достигаемые оптимальным исполь­зованием ресурсов и означающие ее применимость для встроенных систем. Драй­веры и менеджеры можно запускать и удалять (кроме файловой системы) дина­мически, из командной строки. Вы можете иметь только тот сервис, который вам реально нужен, причем это не требует серьезных усилий и не порождает проблем.

Расширяемость и надежностьодновременно, поскольку написанный вами драйвер не нужно компилировать в ядро. Менеджеры ресурсов (сервис логиче­ского уровня) работают в кольце защиты 3, и возможно добавлять свои, не опаса­ясь за систему. Драйверы работают в кольце с уровнем привилегий 1 и могут вы­звать проблемы, но не фатального характера. Кроме того, их достаточно просто писать и отлаживать.

Быстрый сетевой протокол FLEET, прозрачный для обмена сообщения­ми, автоматически обеспечивающий отказоустойчивость, балансирование нагруз­ки и маршрутизацию между альтернативными путями доступа.

Компактная графическая подсистема Photon, построенная на тех же принципах модульности, что и сама ОС, позволяет получить полнофункциональ­ный графический интерфейс пользователя GUI, работающий вместе с POSIX-совместимой ОС всего в 4 Мбайт памяти, начиная с i80386 процессора.

Основными принципами, которые являются обязательными при реализации и создании ОСРВ являются:

Первым обязательным требованием к архитектуре ОСРВ является многоза­дачность. Очевидно, что варианты с псевдомногозадачностью (а точнее - не вытесняющая многозадачность) типа MS Windows 3.x или Novell NetWare неприем­лемы, поскольку они допускают возможность блокировки или даже полного раз­вала системы одним неправильно работающим процессом. Для предотвращения блокировок ОСРВ должна использовать квантование времени (то есть вытесняю­щую многозадачность).

Вторая проблема (организация надежных вычислений) может быть эффек­тивно решена при полном использовании возможностей процессоров Intel 80386 и старше, что предполагает работу ОС в 32-разрядном режиме процессора. Для эф­фективного обслуживания прерываний ОС должна использовать алгоритм дис­петчеризации, обеспечивающий вытесняющее планирование, основанное на при­оритетах. Крайне желательны эффективная поддержка сетевых коммуникаций и наличие развитых механизмов взаимодействия между процессами, поскольку ре­альные технологические системы обычно управляются целым комплексом ком­пьютеров и/или контроллеров. Важно, чтобы ОС поддерживала множественные потоки управления (не только мультипрограммный, но и мультизадачный режи­мы), а также симметричную мультипроцессорность.

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

2. Архитектура системы QNX

QNX - это ОС реального времени, позволяющая эффективно организовать распределенные вычисления. В системе реализована концепция связи между за­дачами на основе сообщений, посылаемых oт одной задачи к другой, причем за­дачи эти могут находиться как на одном и том же компьютере, так и на удален­ных, но связанных локальной вычислительной сетью. Реальное время и концеп­ция связи между процессами в виде сообщений оказывают решающее влияние на разрабатываемое для QNX программное обеспечение и на программиста, стремя­щегося с максимальной выгодой использовать преимущества системы.

Микроядро имеет объем и несколько десятков килобайт (в одной из версий - 10 Кбайт, в другой - менее 32 Кбайт), то есть это одно из самых маленьких ядер среди всех существующих операционных систем. В этом объеме помещаются:

.механизм передачи сообщений между процессами (IPC);

.редиректор прерываний;

.блок планирования выполнением задач;

.сетевой интерфейс для перенаправления сообщений (менеджер Net).

Механизм передачи межпроцессорныхсообщений занимается пересыл­кой сообщений между процессами и является одной из важнейших частей опера­ционной системы, так как все общения между процессами, в том числе и систем­ными, происходит через сообщения. Сообщение в QNX - это последовательность байтов произвольной длины (0-65 535 байтов) произвольного формата. Протокол обмена сообщениями выглядит таким образом. Например, задача блокируется для ожидания сообщения. Другая же задача посылает первой сообщение и при этом блокируется сама, ожидая ответа. Первая задача разблокируется, обрабатывает сообщение и отвечает, разблокируя при этом вторую задачу.

Сообщения и ответы, пересылаемые между процессами при их взаимодей­ствии, находятся в теле отправляющего их процесса до того момента, когда они могут быть приняты. Это значит, что, с одной стороны, уменьшается вероятность повреждения сообщения в процессе передачи, а с другой - уменьшается объем оперативной памяти, необходимый для работы ядра. Кроме того, уменьшается число пересылок из памяти в память, что разгружает процессор. Особенностью процесса передачи сообщений является то, что в сети, состоящей из нескольких компьютеров под управлением QNX, сообщения могут прозрачно передаваться процессам, выполняющимся на любом из узлов. Определены в QNX еще и два дополнительных метода передачи сообщений - метод представителей(Proxy) и метод сигналов(Signal).

Представители используются в случаях, когда процесс должен передать со­общение, но не должен при этом блокироваться на передачу. В таком случае вы­зывается функция qnx_proxy_attach( )и создается представитель. Он накапливает в себе сообщения, которые должны быть доставлены другим процессам. Любой процесс, знающий идентификатор представителя, может вызвать функцию Trig-ger( ),после чего будет доставлено первое в очереди сообщение. Функция Trigger( )может вызываться несколько раз, и каждый раз представитель будет доставлять следующее сообщение. При этом представитель содержит буфер, в ко­тором может храниться до 65 535 сообщений.

Как известно, сигналы уже давно используются и ОС UNIX. Система QNX поддерживает множество сигналов, совместимых с POSIX, большое количество сигналов, традиционно использовавшихся в UNIX (поддержка этих сигналов реа­лизована для совместимости с переносимыми приложениями, и ни один из сис­темных процессов QNX их не генерирует), а также несколько сигналов, специ­фичных для самой QNX. По умолчанию любой сигнал, полученный процессом, приводит к завершению процесса (кроме нескольких сигналов, которые по умол­чанию игнорируются). Но процесс с приоритетом уровня «superuser» может защи­титься от нежелательных сигналов. В любом случае процесс может содержать об­работчик для каждого возможного сигнала. Сигналы удобно рассматривать как разновидность программных прерываний.

Редиректор прерыванийявляется частью ядра и занимается перенаправ­лением аппаратных прерываний в связанные с ними процессы. Благодаря такому подходу возникает один побочный эффект - с аппаратной частью компьютера ра­ботает ядро, оно перенаправляет прерывания процессам - обработчикам прерыва­ний. Обработчики прерываний обычно встроены в процессы, хотя каждый из них исполняется асинхронно с процессом, в который он встроен. Обработчик испол­нялся в контексте процесса, и имеет доступ ко всем глобальным переменным процесса. При работе обработчика прерываний прерывания paзрешены, но обра­ботчик приостанавливается только в том случае, если произошло более высоко­приоритетное прерывание. Если это позволяется аппаратной частью, к одному прерыванию может быть подключено несколько обработчиков, и каждый из них получит управление при возникновении прерывания.

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

Блок планирования выполнения задач(диспетчер задач) занимается обеспечением многозадачности. В этой части ОС QNX предоставляет разработчи­ку огромный простоp для выбора той методики выделения ресурсов процессора задаче, которая обеспечит наиболее подходящие условия для критических прило­жений или обеспечит такие условия для некритических приложений, что они вы­полнятся за разумное время, не мешая работе критических приложений.

К выполнению своих функций как диспетчера ядро приступает в следую­щих случаях:

.какой-либо процесс вышел из блокированного состояния;

.истек квант времени для процесса, владеющего CPU;

.работающий процесс прерван каким-либо событием.

Диспетчер выбирает процесс для запуска среди неблокированных процес­сов в порядке значении их приоритетов, которые располагаются в диапазоне oт 0 (наименьший) до 31 (наибольший). Обслуживание каждого из процессов зависит от метода диспетчеризации, с которым он работает (уровень приоритета и метод диспетчеризации могут динамически меняться во время работы). В QNX сущест­вуют три метода диспетчеризации: FIFO(первым пришел - первым обслужен), round-robin(процессу выделяется определенный квант времени для работы) и адаптивный, который является наиболее используемым.

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

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

Процесс, работающий с адаптивным методом, в QNX ведет себя следую­щим образом:

1. Когда процесс полностью использовал выделенный ему квант времени, его приоритет снижается на 1, если в системе есть процессы с тем же уровнем приоритета, готовые к исполнению.

2. Если процесс с пониженным приоритетом остается не обслуженным в те­чение секунды, его приоритет увеличивается на 1.

Если процесс блокируется, ему возвращается оригинальное значение при­оритета.

По умолчанию процессы запускаются в режиме адаптивной многозадачно­сти. В этом же режиме работают все системные утилиты QNX. Процессы, рабо­тающие в разных режимах многозадачности, могут одновременно находиться в памяти и исполняться. Важный элемент реализации многозадачности — это при­оритет процесса. Обычно приоритет процесса устанавливается при его запуске. Но есть дополнительная возможность, называемая «вызываемый клиентом при­оритет». Как правило, она реализуется для серверных процессов (исполняющих запросы на какое-либо обслуживание). При этом приоритет процесса-сервера ус­танавливается только на время обработки запроса и становится равным приорите­ту процесса-клиента.

Сетевой интерфейсв системе QNX является неотъемлемой частью ядра. Он взаимодействует с сетевым адаптером через сетевой драйвер, но базовые се­тевые сервисы реализованы на уровне ядра. При этом передача сообщения про­цессу, находящемуся на другом компьютере, ничем не отличается с точки зрения приложения от передачи сообщения процессу, выполняющемуся на том же ком­пьютере. Благодаря такой организации сеть превращается в однородную вычис­лительную среду. При этом для большинства приложений не имеет значения, с какого компьютера они были запущены, на каком исполняются и куда поступают результаты их работы. Такое решение принципиально отличает QNX от осталь­ных ОС, которые тоже имеют все необходимые средства для работы в сети, и де­лает системы, работающие под ее управлением, по-настоящему распределенными. Все сервисы QNX, не реализованные непосредственно в ядре, работают как стандартные процессы в полном соответствии с основными концепциями микро­ядерной архитектуры. С точки зрения операционной системы системные процес­сы ничем не отличаются от всех остальных, как и драйверы устройств. Единст­венное, что нужно сделать, написав новый драйвер устройства в QNX, чтобы он стал частью операционной системы, - это изменить конфигурационный файл сис­темы так, чтобы драйвер запускался при загрузке.

3. Основные механизмы QNX для организации распределенных вычислений QNX является сетевой операционной системой и позволяет организовать эффективные распределенные вычисления. Для организации сети на каждой ма­шине, называемой узлом, помимо ядра и менеджера процессов должен быть за­пущен менеджер Net. Менеджер Net не зависит от аппаратной реализации сети. Данная аппаратная независимость обеспечивается за счет использования сетевых драйверов. В QNX имеются драйверы для различных сетей, например Ethernet, Arcnet, Token Ring. Кроме этого, имеется возможность организации сети через последовательный канал или модем.

В QNX четвертой версии полностью реализовано встроенное сетевое взаи­модействие «точка-точка». Например, находясь на машине А, можно скопировать файл с гибкого диска, подключенного к машине В, на жесткий диск, подключен­ный к машине С. По существу, сеть из машин QNX действует как один мощный компьютер. Любые ресурсы (модемы, диски, принтеры) могут быть добавлены к системе простым их подключением к любой машине в сети. QNX поддерживает одновременную работу в сетях Ethernet, Arcnet, Serial и Token Ring, обеспечивает более чем один-единственный путь для коммуникации, а также балансировку на­грузки в сетях. Если кабель или сетевая плата выходит из строя таким образом, что связь через эту сеть прекращается, то система будет автоматически перена­правлять данные через другую сеть. Это происходит в режиме «on-line», предос­тавляя пользователю автоматическую сетевую избыточность и увеличивая ско­рость коммуникаций во всей системе.

Каждому узлу в сети соответствует уникальный целочисленный идентифи­катор - логический номер узла. Любой поток в сети QNX имеет прозрачный дос­туп (при наличии достаточных привилегий) ко всем ресурсам сети, то же самое относится и к взаимодействию потоков. Для взаимодействия потоков, находящих­ся на разных узлах сети, используются те же самые вызовы ядра, что и для пото­ков, выполняемых на одном узле. В том случае, если потоки находятся на разных узлах сети, ядро переадресует запрос менеджеру сети. Для организации обмена в сети используется надежный и эффективный протокол транспортного уровня FLEET. Каждый из узлов может принадлежать одновременно нескольким QNX-сетям. В том случае если сетевое взаимодействие может быть реализовано не­сколькими путями, для передачи выбирается незагруженная и более скоростная сеть.

Сетевое взаимодействие является узким местом в большинстве операцион­ных систем и обычно создает значительные проблемы для систем реального вре­мени. Для того чтобы обойти это препятствие, разработчики QNX создали собст­венную специальную сетевую технологию FLEET и соответствующий протокол транспортного уровня FTL (FLEET transport laуег). Этот протокол не базируется ни на одном из распространенных сетевых протоколов типа IPX или NetBios и об­ладает рядом качеств, которые делают его уникальным. Основные его качества зашифрованы в аббревиатуре FLEET, которая расшифровывается следующим об­разом.

Благодаря этой технологии сеть компьютеров с QNX фактически можно представлять как один виртуальный суперкомпьютер. Все ресурсы любого из уз­лов сети автоматически доступны другим. Это значит, что любая программа мо­жет быть запущена на любом узле, при этом ее входные и выходные потоки могут быть направлены на любое устройство на любых других узлах.

Например, утилита make в QNX автоматически распараллеливает компиля­цию пакетов из нескольких модулей на все доступные узлы сети, а затем собирает исполняемый модуль по мере завершений компиляции на узлах. Специальный драйвер, входящий в комплект поставки, позволяет использовать для сетевого взаимодействия любое устройство, с которым может быть ассоциирован файло­вый дескриптор, например последовательный порт, что открывает возможность для создания глобальных сетей.

Достигаются все эти удобства за счет того, что поддержка сети частично обеспечивается и микроядром (специальный код в его составе позволяет QNX фактически объединять все микроядра в сети в одно ядро). Разумеется, за такие возможности приходится платить тем, что мы не можем получить драйвер для ка­кой-либо сетевой платы от кого-либо еще, кроме фирмы QSSL, то есть использо­ваться может только то оборудование, которое уже поддерживается. Однако ас­сортимент такого оборудования достаточно широк и периодически пополняется новейшими устройствами.

 

 

Fault-Tolerant Networking QNX может одновременно использовать несколько физических сетей. При выходе из строя любой из них данные будут автома­тически перенаправлены «на лету» через другую сеть
Load- Balancing on the Fly При наличии нескольких физически соединений QNX автомати­чески распараллеливает передачу пакетов по соответствующим сетям
Efficient. Per­formance Специальные драйверы, разрабатываемые фирмой QSSL для широкого спектра оборудования, позволяют с максимальной эф­фективностью использовать сетевое оборудование
Extensable Ar­chitecture Любые новые типы сетей могут быть поддержаны путем добав­ления соответствующих драйверов
Transparent Distributed Proc­essing Благодаря отсутствию разницы между передачей сообщений в пределах одного узла и между узлами нет необходимости вно­сить какие-либо изменения в приложении для того, чтобы они могли взаимодействовать через сеть

 

Когда ядро получает запрос на передачу данных процессу, находящемуся на удаленном узле, оно переадресовывает этот запрос менеджеру Net, в подчинении которого находятся драйверы всех сетевых карт. Имея перед собой полную кар­тину состояния всего сетевого оборудования, менеджер Net может отслеживать состояние каждой сети и динамически перераспределять нагрузку между ними. В случае, когда одна из сетей выходит из строя, информационный поток автомати­чески перенаправляется в другую доступную сеть, что важно при построении вы­соконадежных систем. Кроме поддержки своего собственного протокола, Net обеспечивает передачу пакетов TCP/IP, SMB и многих других, используя то же сетевое оборудование. Производительность QNX в сети приближается к произво­дительности аппаратного обеспечения.

При проектировании системы реального времени, как правило, необходимо обеспечить одновременное выполнение нескольких приложений. В QNX/Neutrino параллельность выполнения достигается за счет использования потоковой модели POSIX, в которой процессы в системе представляются в виде совокупности пото­ков. Поток является минимальной единицей выполнения и диспетчеризации для ядра Neutrino, процесс определяет адресное пространство для потоков. Каждый процесс состоит минимум из одного потока. QNX предоставляет богатый набор функций для синхронизации потоков. В отличие от потоков само ядро не подле­жит диспетчеризации. Код ядра исполняется только в том случае, когда какой-нибудь поток вызывает функцию ядра или при обработке аппаратного прерыва­ния.

QNX базируется на концепции передачи сообщений. Передачу сообщений, а также их диспетчеризацию осуществляет ядро системы. Кроме того, ядро управляет временными прерываниями. Выполнение остальных функций обеспе­чивается задачами-администраторами. Программа, желающая создать задачу, по­сылает сообщение администратору задач (модуль task) и блокируется для ожида­ния ответа. Если новая задача должна выполняться одновременно с порождающей ее задачей, администратор задач task создает ее и, отвечая, выдает порождающей задаче идентификатор (id) созданной задачи. В противном случае никакого сооб­щения не посылается до тех пор, пока новая задача не закончится сама по себе. В этом случае в ответе администратора задач будут содержаться конечные характе­ристики закончившейся задачи.

Сообщения отличаются количеством данных, которые передаются от одной задачи точно к другой задаче. Данные копируются из адресного пространства первой задачи в адресное пространство второй, и выполнение первой задачи при­останавливается до тех пор, пока вторая задача не вернет ответное сообщение. В действительности обе задачи кратковременно взаимодействуют во время выпол­нения передачи. Ничто, кроме длины сообщения (максимальная длина 65 535 байт), не заботит QNX при передаче сообщения. Существует несколько протоко­лов, которые могут быть использованы для сообщений.

Основные операции над сообщениями - это послать, получить и ответить, а также несколько их вариантов для обработки специальных ситуаций. Получатель всегда идентифицируется своим идентификатором задачи, хотя существуют спо­собы ассоциировать имена с идентификатором задачи. Наиболее интересные ва­рианты операций включают в себя возможность получать (копировать) только первую часть сообщения, а затем получать оставшуюся часть такими кусками, ка­кие потребуются. Это может быть использовано для того, чтобы сначала узнать длину сообщения, а затем динамически распределить принимающий буфер. Если необходимо задержать ответное сообщение до тех пор, пока не будет получено и обработано другое сообщение, то чтение первых нескольких байт дает вам ком­пактный «обработчик», через который позже можно получить доступ ко всему сообщению. Таким образом, ваша задача предохраняется от того, чтобы хранить в себе большое количество буферов.

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

Кроме этого, QNX обеспечивает объединение сообщений в структуру дан­ных, называемую очередью. Очередь - это область данных в третьей, отдельной задаче, которая временно принимает передаваемое сообщение и немедленно отве­чает передатчику. В отличие от стандартной передачи сообщений, передатчик не­медленно освобождается для того, чтобы продолжить свою работу. Задача адми­нистратора очереди хранить в себе сообщение до тех пор, пока приемник не будет готов прочитать его. Это он делает путем запроса сообщения у администратора очереди. Любое количество сообщений (ограничено только возможностью памя­ти) может храниться в очереди. Они хранятся и передаются в том порядке, в кото­ром были приняты. Может быть создано любое количество очередей. Каждая оче­редь идентифицируется своим именем.

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

Порт подобен флагу, известному всем задачам на одном и том же узле (но не на различных узлax). Он имеет два состояния, которые могут трактоваться как «присоединить» и «освободить», хотя пользователь может использовать свою ин­терпретацию; например, «занят» и «доступен». Порты используются для быстрой простой синхронизации между задачей и обработчиком прерываний устройства. Они нумеруются от нуля до максимума 32 (на некоторых типах узлов возможно и больше). Первые 20 номеров зарезервированы для использования операционной системой.

С портом могут быть выполнены три операции:

-присоединить порт;

-отсоединить порт;

-послать сигнал в порт.

Одновременно к порту может быть присоединена только одна задача Если другая задача попытается «отсоединиться» от того же самого порта, то произой­дет отказ при вызове функции, и управление вернется к задаче, которая в настоя­щий момент присоединена к этому порту. Это самый быстрый способ обнаружить идентификатор другой задачи, подразумевая, что задачи могут договориться ис­пользовать один номер порта. Все рассматриваемые задачи должны находиться на одном и том же узле. При работе нескольких узлов специальные функции обеспе­чивают большую гибкость и эффективность.

Любая задача может посылать сигнал в любой порт независимо от того, бы­ла ли она присоединена к нему или нет (предпочтительно, чтобы не была присое­динена). Сигнал подобен не блокирующей передаче пустого сообщения. То есть передатчик не приостанавливается, а приемник не получает какие-либо данные, он только отмечает, что конкретный порт изменил свое состояние.

Задача, присоединенная к порту, может ожидать прибытия сигнала или мо­жет периодически читать порт. QNX хранит информацию о сигналах, передавае­мых в каждый порт, и уменьшает счетчик после каждой операции «приема» сиг­нала («чтение» возвращает счетчик и устанавливает его в ноль). Сигналы всегда принимаются перед сообщениями, давая им тем самым больший приоритет над сообщениями. В этом смысле сигналы часто используются обработчиками преры­ваний для того, чтобы оповестить задачу о внешних (аппаратных) событиях (дей­ствительно, обработчики прерываний не имеют возможности посылать сообще­ния и должны использовать сигналы).

В отличие oт описанных выше методов, которые строго синхронизируются, «исключения» обеспечивают асинхронное взаимодействие. То есть исключение может прервать нормальное выполнение потока задачи. Они, таким образом, яв­ляются аварийными событиями. QNX резервирует для себя 16 исключений для того, чтобы оповещать задачи о прерывании с клавиатуры, нарушении памяти и подобных необычных ситуациях. Остальные 16 исключений могут быть определены и использованы прикладными задачами.

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

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

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

Благодаря такому свойству QNX, как возможность обмена посланиями ме­жду задачами и узлами сети, программы не заботятся о конкретном размещении ресурсов в сети. Это свойство придает системе необычную гибкость. Так, узлы могут произвольно добавляться и изыматься из системы, не затрагивая системные программы. QNX приобретает эту конфигурационную независимость благодаря применению концепции о «виртуальных» задачах. У виртуальных задач непо­средственный код и данные, будучи на одном из удаленных узлов, возникают и ведут себя так, как если бы они были локальными задачами какого-то узла со все­ми атрибутами и привилегиями. Программа, посылающая сообщение в сети, ни­когда не посылает его точно. Сначала она открывает «виртуальную цепочку». Виртуальная цепочка включает все виртуальные задачи, связанные между собой. На обоих концах такой связи имеются буферы, которые позволяют хранить самое большое послание из тex, которые цепочка может нести в данном сеансе связи. Сетевой администратор помещает в эти буферы все сообщения для соединенных задач. Виртуальная задача, таким образом, занимает всего лишь пространство, не­обходимое для буфера и входа в таблицу задач. Чтобы открыть связь, необходимо знать идентификатор узла и задачи, с которой устанавливается связь. Для этого необходимо знать идентификатор задачи администратора, ответственного за дан­ную функцию, или глобальное имя сервера. Не раскрывая здесь подробно меха­низм обмена посланиями, добавим, что наша задача может вообще выполняться на другом узле, где имеется более совершенный процессор.

Контрольные вопросы:

1. Перечислите основные параметры операционных систем реального вре­мени.

2. Дайте характеристику времени реакции системы на прерывание.

3. Поясните смысл параметра операционных систем реального времени «время переключения контекста».

4. Приведите примеры размера ядра операционных систем реального вре­мени.

5. Дайте характеристику механизмам систем реального времени.

6. Что понимается под идеальной операционной системой реального време­ни?

7. Какие параметры указываются в каждом описателе операционных систем реального времени?

8. Какие алгоритмы планирования операционных систем Вам известны? Дайте их характеристику.

9. Дайте характеристику механизмам межзадачного взаимодействия опера­ционных систем реального времени.

10. Какие базовые концепции операционных систем реального времени Вы знаете?

11. Дайте характеристику монолитной архитектуре операционных систем реального времени. Нарисуйте ее модель.

12. Перечислите основные достоинства и недостатки монолитной архитек­туры.

13. Какие недостатки имеет ОСРВ модульной архитектуры на основе мик-

роядра?

14. Как осуществляется взаимодействие между компонентами системы и пользовательскими процессами в объектной архитектуре на основе объектов-микроядер?

15. Дайте характеристику ОСРВ объектной архитектуры на основе объек­тов-микроядер.

1. Почему про QNX часто говорят «сетевая» ОС?

2. Что такое сетевой протокол FLEET? 10.Какие функции реализует ядро QNX?

11.В чем вы видите принципиальные отличия между ядром Windows NT 4.0, которое считают построенным по микроядерным принципам, от ядра QNX?

12.Расскажите об основных механизмах, которые имеются и QNX для орг низации распределенных вычислений.


Тема 4. Особенности программирования систем реального времени

Лекция 4.1. Методы программирования в реальном времени.

1. Последовательное программирование и программирование задач ре­ального времени

2. Среда программирования.

3. Структура программы реального времени.

4. Параллельное программирование, мультипрограммирование и мно­гозадачность.

 

1. Последовательное программирование и программирование задач ре­ального времени

Программа представляет собой описание объектов - констант и пере­менных - и операций, совершаемых над ними. Таким образом, программа -это чистая информация. Ее можно записать на какой-либо носитель, напри­мер на бумагу или на дискету.

Программы можно создавать и анализировать на нескольких уровнях абстракции (детализации) с помощью соответствующих приемов формально­го описания переменных и операций, выполняемых на каждом уровне. На самом нижнем уровне используются непосредственное описание - для каж­дой переменной указывается ее размер и адрес в памяти. На более высоких уровнях переменные имеют абстрактные имена, а операции сгруппированы в функции или процедуры. Программист, работающий на высоком уровне аб­стракции, не должен думать о том, по каким реальным адресам памяти хра­нятся переменные, и о машинных командах, генерируемых компилятором.

Последовательное программирование(sequential programming) явля­ется наиболее распространенным способом написания программ. Понятие "последовательное" подразумевает, что операторы программы выполняются в известной последовательности один за другим. Целью последовательной программы является преобразование входных данных, заданных в опреде­ленной форме, в выходные данные, имеющие другую форму, в соответствии с некоторым алгоритмом - методом решения (рис. 1).

Рисунок 1. - Обработка данных последовательной программой

 

Таким образом, последовательная программа работает как фильтр для исходных данных. Ее результат и характеристики полностью определяются входными данными и алгоритмом их обработки, при этом временные показа­тели играют, как правило, второстепенную роль. На результат не влияют ни инструментальные (язык программирования), ни аппаратные (быстродейст­вие ЦП) средства: от первых зависят усилия и время, затраченные на разра­ботку и характеристики исполняемого кода, а от вторых - скорость выполне­ния программы, но в любом случае выходные данные будут одинаковыми.

Программирование в реальном времени(real-time programming) от­личается от последовательного программирования - разработчик программы должен постоянно иметь в виду среду, в которой работает программа, будь то контроллер микроволновой печи или устройство управления манипулято­ром робота. В системах реального времени внешние сигналы, как правило, требуют немедленной реакции процессора. В сущности, одной из наиболее важных особенностей систем реального времени является время реакции на входные сигналы, которое должно удовлетворять заданным ограничениям.

Специальные требования к программированию в реальном времени, в частности необходимость быстро реагировать на внешние запросы, нельзя адекватно реализовать с помощью обычных приемов последовательного про­граммирования. Насильственное последовательное расположение блоков программы, которые должны выполняться параллельно, приводит к неесте­ственной запутанности результирующего кода и вынуждает связывать между собой функции, которые, по сути, являются самостоятельными. В большин­стве случаев применение обычных приемов последовательного программирования не позволяет построить систему реального времени. В таких систе­мах независимые программные модули или задачи должны быть активными одновременно, то есть работать параллельно, при этом каждая задача выпол­няет свои специфические функции. Такая техника известна под названием параллельного программирования (concurrent programming). В названии де­лается упор на взаимодействие между отдельными программными модулями. Параллельное исполнение может осуществляться на одной или нескольких ЭВМ, связанных распределенной сетью.

Программирование в реальном времени представляет собой раздел мультипрограммирования, который посвящен не только разработке взаимо­связанных параллельных процессов, но и временным характеристикам сис­темы, взаимодействующей с внешним миром.

Между программами реального времени и обычными последователь­ными программами, с четко определенными входом и выходом, имеются су­щественные различия. Перечислим отличия программ реального времени от последовательных программ:

1. Логика исполнения программы определяется внешними событиями.

2. Программа работает не только с данными, но и с сигналами, посту­пающими из внешнего мира, например, от датчиков.

3. Логика развития программы может явно зависеть от времени.

4. Жесткие временные ограничения. Невозможность вычислить резуль­тат за определенное время может оказаться такой же ошибкой, как и невер­ный результат ("правильный ответ, полученный поздно - это неверный от­вет").

5. Результат выполнения программы зависит от общего состояния сис­темы, и его нельзя предсказать заранее.

6. Программа, как правило, работает в многозадачном режиме. Соот­ветственно, необходимы процедуры синхронизации и обмена данными меж­ду процессами.

7. Исполнение программы не заканчивается по исчерпании входных данных - она всегда ждет поступления новых данных.

Важность фактора времени не следует понимать как требование высо­кой скорости исполнения программы. Скорость исполнения программы ре­ального времени должна быть достаточной для того, чтобы в рамках уста­новленных ограничений реагировать на входные данные и сигналы и выраба­тывать соответствующие выходные величины. "Медленная" система реаль­ного времени может великолепно управлять медленным процессом. Поэтому скорость исполнения программ реального времени необходимо рассматри­вать относительно управляемого процесса или необходимой скорости. Ти­пичные приложения автоматизации производственных процессов требуют гарантированное время ответа порядка 1 мс, а в отдельных случаях - порядка 0.1 мс. При программировании в реальном времени особенно важными явля­ется эффективность и время реакции программ. Соответственно, разработка программ тесно связана с параметрами операционной системы, а в распреде­ленных системах - и локальной сети.

Особенности программирования в реальном времени требуют специ­альной техники и методов, не использующихся при последовательном про­граммировании, которые относятся к влиянию на исполнение программы внешней среды и временных параметров. Наиболее важными из них являют­ся перехват прерываний, обработка исключительных (нештатных) ситуаций и непосредственное использование функций операционной системы (вызовы ядра из прикладной программы, минуя стандартные средства). Помимо этого при программировании в реальном времени используются методика мульти­программирования и модель "клиент-сервер", поскольку отдельный процесс или поток обычно выполняют только некоторую самостоятельную часть всей задачи.

2. Среда программирования

Рассмотрим среду, в которой исполняются программы. Среда выпол­нения может варьироваться от мини-, персональных и одноплатных микрокомпьютеров и локальных шин, связанных с окружающей средой через аппа­ратные интерфейсы, до распределенных систем "клиент-сервер" с централи­зованными базами данных и доступом к системе высокопроизводительных графических рабочих станций. В комплексной системе управления промыш­ленными и технологическими процессами может одновременно использо­ваться все перечисленное оборудование.

Разнообразие аппаратной среды отражается и в программном обеспе­чении, которое включает в себя как программы, записанные в ПЗУ, так и комплексные операционные системы, обеспечивающие разработку и испол­нение программ. В больших системах создание и исполнение программ осу­ществляются на одной и той же ЭВМ, а в некоторых случаях даже в одно время. Небольшие системы могут не иметь средств разработки, и программы для них должны создаваться на более мощных ЭВМ с последующей загруз­кой в исполняющую систему. То же касается и микропрограмм, "зашитых" в ПЗУ оборудования производителем (firmware), - они разрабатываются на ЭВМ, отличной от той, на которой исполняются.

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

Важно как можно раньше выяснить функции, обеспечиваемые имею­щейся средой, и возможные альтернативы. Например, микропроцессор Mo­torola 68000 имеет в своем наборе команд инструкцию test_and_set, и поэто­му связь между задачами может осуществляться через общие области памя­ти. Операционная система VAX/VMS поддерживает почтовые ящики, и син­хронизировать процессы можно с помощью механизма передачи сообщений.

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

Из-за того, что многозадачные системы и системы реального времени разрабатываются коллективами программистов, необходимо с самого начала добиваться ясности, какие методы и приемы используются.

Структурирование аппаратных и программных ресурсов, то есть при­своение адресов на шине и приоритетов прерываний для интерфейсных уст­ройств, имеет важное значение. Неправильный порядок распределения ре­сурсов может привести к тупиковым ситуациям. Определение аппаратных адресов и относительных приоритетов прерываний не зависит от разрабаты­ваемой программы. Поэтому оно должно быть произведено на ранней стадии и зафиксировано в техническом задании. Его не следует откладывать до мо­мента непосредственного кодирования, так как в этом случае неизбежны конфликты между программными модулями и возникает риск тупиковых си­туаций.

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

Программы следует строить по принципам, применяемым в операци­онных системах, - на основе модульной и многоуровневой структуры, поскольку это существенно упрощает разработку сложных систем. Должна быть определена спецификация отдельных модулей, начиная с интерфейсов между аппаратными и программными компонентами системы. К основной информации об интерфейсах относится и структура сообщений, которыми будут обмениваться программные модули. Это не означает, что изменения в определении интерфейсов не могут вводиться после начала разработки про­граммы. Но чем позже они вносятся, тем больше затрат потребует изменение кода, тестирование и т. д. С другой стороны, следует быть готовым к тому, что некоторые изменения спецификаций все равно будут происходить в про­цессе разработки программы, поскольку продвижение в работе позволяет лучше увидеть проблему.

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

3. Структура программы реального времени

Разработка программы реального времени начинается с анализа и опи­сания задачи. Функции системы делятся на простые части, с каждой из кото­рых связывается программный модуль.

Например, задачи для управления движением манипулятора робота можно организовать следующим образом:

– считать с диска описание траекторий;

– рассчитать следующее положение манипулятора (опорное значение);

– считать с помощью датчиков текущее положение;

– вычислить необходимый сигнал управления;

– выполнить управляющее действие;

– проверить, что опорное значение и текущее положение совпадают в пределах заданной точности;

– получить данные от оператора;

– остановить робота в случае нештатной ситуации (например, сигнал прерывания от аварийной кнопки).

Принципиальной особенностью программ реального времени является постоянная готовность и отсутствие условий нормального, а не аварийного завершения. Если программа не исполняется и не обрабатывает данные, она остается в режиме ожидания прерывания/события или истечения некоторого интервала времени. Программы реального времени - это последовательный код, исполняющийся в бесконечном цикле.

В каком-то месте программы есть оператор, приостанавливающий ис­полнение до наступления внешнего события или истечения интервала време­ни. Обычно программа структурируется таким образом, что оператор endникогда не достигается

while true do(*бесконечный цикл*) begin(*процедура обработки*) waitevent at #2,28 (*внешнее прерывание*) (*код обработки*) … end; (*процедура обработки*)

end. (*выход из программы; никогда не достигается*)

При разработке каждого программного модуля должны быть четко вы­делены области, в которых происходит обращение к защищенным ресурсам, - критические секции. Вход и выход из этих областей координируется каким-либо методом синхронизации или межпрограммных коммуникаций, напри­мер с помощью семафоров. В общем случае, если процесс находится в критической секции, можно считать, что данные, с которыми он работает, не из­меняются каким-либо другим процессом. Прерывание исполнения процесса не должно оказывать влияния на защищенные ресурсы. Это снижает риск системных ошибок.

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

Для гарантии живучести программы нештатные ситуации, которые мо­гут блокировать или аварийно завершить процесс, должны своевременно распознаваться и исправляться - если это возможно - в рамках самой про­граммы.

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

При другом подходе в память загружается лишь одна копия подпро­граммы, но доступ к ней возможен из разных программ. Такие подпрограм­мы должны быть повторно входимыми - реентерабельными (reentrant), то есть допускать многократные вызовы и приостановку исполнения, которые не влияют друг на друга. Эти программы должны использовать только реги­стры процессора или память вызывающих процессов, то есть не иметь ло­кальных переменных. В результате реентерабельный модуль, разделяемый несколькими процессами, можно прервать в любое время и продолжить с другой точки программы, поскольку он работает со стеком вызвавшего его процесса. Таким образом, реентерабельная процедура может оказаться одно­временно в контексте нескольких различных процессов.

Эффективность исполнения является одним из наиболее важных пара­метров систем реального времени. Процессы должны выполняться быстро, и часто приходится искать компромисс между ясностью и структурированностью программы и ее быстродействием. Жизненный опыт показывает, что если для достижения цели нужно чем-то пожертвовать, что обычно и делает­ся. Не всегда возникает противоречие между структурностью и эффективно­стью, но если первое должно быть принесено в жертву второму, необходимо полностью документировать все принятые решения, иначе существенно ос­ложняется дальнейшее сопровождение программы.

4. Параллельное программирование, мультипрограммирование и мно­гозадачность

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

Мультипрограммирование (multiprogramming) или многозадачность (multitasking) есть способ одновременного исполнения нескольких процес­сов. Такого эффекта можно добиться как для одного, так и для нескольких процессоров: процессы исполняются либо на одном, либо на нескольких свя­занных между собой процессорах. В действительности многие современные вычислительные системы состоят из нескольких процессоров, связанных ме­жду собой либо сетью передачи данных, либо общей шиной.

Для записи параллельных процессов можно использовать следующую нотацию

Cobegin

х := 1; х := 2; х := 3;

coend;

write (x);

Исполнение команд между ключевыми словами cobeginи coendпро­исходит параллельно (рис. 2). Пара операторных скобок cobegin-coendприводит к генерации потоков в рамках многозадачной системы. Оператор cobe-ginне накладывает условий на относительный порядок исполнения отдель­ных процессов, а оператор coendдостигается только тогда, когда все процес­сы внутри блока завершены. Если бы исполнение было последовательным, то окончательное значение переменной х было бы равно 3. Для параллельных процессов конечный результат однозначно предсказать нельзя; задачи вы­полняются, по крайней мере, с внешней точки зрения, в случайной последо­вательности. Поэтому окончательное значение х в приведенном примере мо­жет быть как 1, так и 2 или 3.

Рисунок 2. - Граф очередности для операторов cobegin – coend

Иногда в технической литературе термин "параллельное программиро­вание" используется как синоним мультипрограммирования. Однако эти по­нятия несколько различаются по смыслу. Параллельное программирование -это абстрактный процесс разработки программ, который потенциально может исполняться параллельно, вне зависимости от программно-аппаратной сре­ды. Иными словами, предполагается, что каждая задача реализуется на соб­ственном виртуальном процессоре. С другой стороны, мультипрограммиро­вание представляет собой практический способ исполнения нескольких про­грамм на одном центральном процессоре или в распределенной вычисли­тельной системе. Параллельное программирование более трудоемко, чем по­следовательное, поскольку способность человека следить за развитием свя­занных процессов, и исследовать их взаимодействие, ограничена.

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


Лекция 4.2. Языки программирования реального времени

1. Требования к языкам программирования реального времени.

2. Языки разработки для систем реального времени.

 

1. Требования к языкам программирования реального времени Основными критериями при выборе языка для разработки приложения реального времени являются:

1. Получение наивысшей производительностиприложения реально­го времени. Из этого требования вытекает, что язык должен быть компили­руемого (как C, C++), а не интерпретируемого (как Java) типа, и для него должен существовать компилятор с высокой степенью оптимизации кода. Для современных процессоров качество компилятора особенно важно, по­скольку для них оптимизация может ускорять работу программы в несколько раз по сравнению с не оптимизированным вариантом, причем часто оптими­зирующий компилятор может породить код более быстрый, чем написанный на ассемблере. Технологии оптимизации развиваются достаточно медленно и часто требуются годы на разработку высокоэффективного компилятора. По­этому обычно для более старых и с более простой структурой языков имеют­ся более качественные компиляторы, чем для достаточно молодых, и сложно устроенных языков.

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

3. Возможность вызова процедур, написанных на другом языке, на­пример, на языке ассемблера. Из этого требования вытекает, что последова­тельность вызова подпрограмм (механизм именования объектов, передачи аргументов и получения возвращаемого значения) должна быть документи­рована для выбранного языка.

4. Переносимость приложения, под которой обычно понимают, как

возможность его скомпилировать другим компилятором, имеющимся на той же платформе, так и возможность его скомпилировать на другой платформе и/или другой операционной системе.

5. Поддержка объектно-ориентированного подходастала в послед­нее время необходимостью, зачастую выходя в списке требований на первое место. Это объясняет использование языка Java в ОСРВ.

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

– описание параллельных процессов;

– переключение процессов на основе динамических приоритетов, ко­торые могут изменяться, в том числе и прикладными процессами;

– синхронизацию процессов;

– обмен данными между процессами;

– функции, связанные с часами и таймером, абсолютное и относитель­ное время ожидания;

– прямой доступ к внешним аппаратным портам;

– обработку прерываний;

– обработку исключений.

Немногие языки обеспечивают все эти возможности. Большинство имеет лишь часть из них, хотя для определенных приложений этого оказы­вается достаточно. Некоторые компании разработали специальные языки для поддержки своих собственных аппаратных средств. Эти языки не пре­тендуют на универсальность и ориентированы скорее на конкретные ЭВМ и их интерфейсы. Обычно они базируются на существующих языках - FOR­TRAN, BASIC - с расширениями, включающими функции реального време­ни, о чем свидетельствуют их названия типа "Process BASIC" и "Real-time FORTRAN". Некоторые языки не поддерживают программирования в реальном времени в строгом смысле, но они легко расширяются, например С и C++.

В 1970-е годы широкую поддержку получила концепция единого пе­реносимого многоцелевого языка программирования. В результате был раз­работан язык ADA. Его главная идея состоит в том, что среда программиро­вания, то есть язык, должна быть полностью отделена от аппаратных средств. Программист не должен сталкиваться с деталями машинного уров­ня, а работать только в терминах абстрактных структур и типов данных.

Опыт показал не реалистичность такого подхода. Универсальные, сильно типизированные языки программирования гарантируют определен­ный уровень надежности программы, но в то же время ограничивают гиб­кость. Быстрое развитие технических средств, предъявляет новые требова­ния, которые не могли быть предусмотрены в существующих языках, и мно­гие программисты чувствуют ограничения, используя, не самые современ­ные языки программирования. Цена надежности языка - сложность и гро­моздкость, а генерируемый при этом компилятором код - избыточен и мало­эффективен. Открытый язык типа С, основанный на ограниченном количе­стве базовых идей, обладает большей гибкостью и предоставляет опытному программисту больше возможностей. Не существует наилучшего языка -для каждого приложения и среды необходимо подбирать свои средства и при этом учитывать квалификацию и предпочтения разработчиков.

2. Языки разработки для систем реального времени

Ассемблер.Обеспечивает получение наивысшей производительности, прямой доступ к оборудованию, возможность вызова любых процедур на других языках. Однако, приложения получаются не переносимыми, объект­но-ориентированный подход отсутствует. Обычно ассемблер используется только для написания небольших и четко локализованных фрагментов при­ложения, таких, как обработчики прерываний, драйверы устройств, критические по времени исполнения секции.

Язык программирования ADA.Первым полным языком программи­рования в реальном времени является ADA. В середине 1970-х годов Мини­стерство обороны США для сокращения расходов на разработку и сопрово­ждение своих систем управления реального времени приняло решение вве­сти единый язык программирования в качестве альтернативы сотням ис­пользовавшихся тогда языков. В 1979 году министерство одобрило предло­жения, выдвинутые французской компанией Honeywell Bull. Язык назван в честь Августы Ады Байрон, графини Лавлейс (Augusta Ada Byron, Countess of Lovelace, 1815-1852), которую можно считать первым программистом в истории - она писала программы для аналитической машины (механическо­го компьютера, который никогда не был построен), спроектированной анг­лийским изобретателем Чарльзом Бэббиджем (Charles Babbage).

Язык ADA является полной средой разработки программ с текстовым редактором, отладочными средствами, системой управлениями библиотека­ми и т.д. Спецификации ADA закреплены американским стандартом ANSI/MIL-STD-1815A и включают средства контроля соответствия этому стандарту. Не допускаются диалекты языка - для сертификации компилятор должен правильно выполнить все эталонные тесты.

Структура языка ADA похожа на структуру языка Pascal, но его воз­можности значительно шире, в особенности применительно к системам ре­ального времени. Процессу в ADA соответствует задача, которая выполня­ется независимо от других задач на выделенном виртуальном процессоре, то есть параллельно с другими задачами. Задачи могут быть связаны с отдель­ными прерываниями и исключениями, и работать как их обработчики.

Новым понятием, введенным в ADA, является пакет - модуль со свои­ми собственными описаниями типов данных, переменных и подпрограмм, в котором явно указано, какие из программ и переменных доступны извне. Па­кеты могут компилироваться отдельно с последующим объединением в один исполняемый модуль. Это средство поддерживает модульную разработку программ и создание прикладных библиотек. В начале 1990-х годов язык ADA был пополнен новыми функциями для объектно-ориентированного программирования и программирования в реальном времени.

Машинно-ориентированное программирование низкого уровня под­держивается ADA не достаточно эффективно - это следствие постулата, что все задачи должны решаться средствами высокого уровня. Например, для операций ввода/вывода в ADA используются прикладные пакеты с заранее определенными функциями для управления аппаратными интерфейсами и доступа к внешним данным.

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

Языки С и C++.Язык программирования С, несмотря на отсутствие в нем многих средств, которые теоретики считают необходимыми для хороше­го языка программирования, пользуется большим успехом, начиная с 1980-х годов и по настоящее время. Этот язык стал популярным для всех приложе­ний, требующих высокой эффективности, в частности для программ реально­го времени. Для обычных микропроцессоров, используемых в системах управления, имеются С-компиляторы и системы разработки многих произво­дителей. В промышленности существует явная тенденция к широкому при­менению языка С и операционной системы UNIX, которая сама написана на С, поскольку приложения, написанные на С, машинно-независимы и требуют не больших усилий для адаптации к работе в различной аппаратной среде.