Главная страница  Цифровые системы 

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36] [37] [38] [39] [40] [41] [42] [43] [44] [45] [46] [47] [48] [49] [50] [51] [52] [53] [54] [55] [56] [57] [58] [59] [60] [61] [62] [63] [64] [65] [66] [67] [68] [69] [70] [71] [ 72 ] [73] [74] [75] [76] [77] [78] [79] [80] [81] [82] [83] [84] [85] [86] [87] [88] [89] [90]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Другой пример приведен в разделе 2.1. Пресс для производства пластмассовых изделий контролируется двумя программами, управляемыми по прерыванию. При анализе стало ясно, что решение, основанное на применении только одной программы, неприемлемо.

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

while true do (* бесконечный цикл *) begin (* процедура обработки *)

wait event at #2,28 (* внешнее прерывание *)

(* код обработки *)

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

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

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

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

Щие переменные породившего их процесса, и поэтому программист должен ре-ть, защищать эти переменные или нет.

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

УЮщий раздел.

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



ветствующими модулями после компиляции. При этом в памяти хранится нескодь) копий одной подпрограммы.

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

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

10.6.4. Обработка прерываний и исключений

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

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

Получение данных по прерыванию {interrupt) происходит иначе. Интерфейсное устройство, получившее новые данные, привлекает внимание ЦП, посылая ему сиг нал прерывания через системную шину. По отношению к текущему процессу "РР вания являются асинхронными событиями, требующими немедленной реакции, лучив сигнал прерывания, процессор приостанавливает исполнение екуш процесса, сохраняет в стеке его контекст, считывает из таблицы адрес ПР°Р. работки прерывания и передает ей управление. Эта программа называется обра чиком прерывания {intermpt handler). Другой вариант обработки прерываний чается в том, что планировщик выбирает из очереди ожидания этого события

--------.ттаГГПВ.

эрывания следующий ирицсии и iicpuu«.fii -. „

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

чается в том, 4iu ujmnyipuDiijjriiv i.v.i-v-. ----г- „гпв Уиитп

прерывания следующий процесс и переводит его в очередь готовых процессо- <лу.

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

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

Реакция на исключения {exceptions) похожа на обработку прерываний. Исключениями называются нештатные ситуации, когда процессор не может правильно выполнить команду. Примером исключения является деление на ноль или обращение по несуществующему адресу. В англоязычной литературе для разных видов исключений применяются термины trap, fault, abort.

Обычно операционная система обрабатывает исключения, прекращая текущий процесс, и выводит сообщение, четко описывающее ситуацию, на устройство отображения, обычно монитор или принтер. Приемлемая при интерактивной многопользовательской последовательной обработке, внезапная остановка процесса в системах реального времени должна быть абсолютно исключена. Нельзя допустить, чтобы управляемые микропроцессором автопилот самолета или автоматическая тормозная <истема автомобиля {Automatic Braking System - KBS) внезапно прекратили работу из-а деления на ноль. В системах реального времени все возможные исключения должны анализироваться заранее с определением соответствующих процедур обработки.

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

*Пуск адреса программных модулей известны только после их загрузки. При

агруж системы в таблицу обработки прерываний записываются адреса памяти, куда Ожаются обработчики, которые затем вызываются по ссылкам из этой таблицы

Не путать с "взаимным исключением" - mutual exclusion -

5 3ак

ИЗ раздела 10.3.2. - Примеч. ред.

ак 1021



10.6.5. Программирование операций ожидания

Процесс реального времени может явным образом ждать истечения некоторо;. интервала (относительное время) или наступления заданного момента (абсолютно время). Соответствующие функции обычно имеют следующий формат:

wait (и)

Этот принцип проиллюстрирован на рис. 10.96, где номинальное время отложено до горизонтальной оси. Когда абсолютное время принимается в качестве опорного.

)сопления ощибок времени удается избежать.

ошибка

ошибка

исполнение

- исполнение

I исполнение

ждать в течение интервала Т

ждать в течение интервала Т

wait until (время)

где п - интервал в секундах или миллисекундах, а переменная время" имеет формат часы, минуты, секунды, миллисекунды

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

Распространенный, но не лучщий метод организации временной задержки -цикл, контроль системного времени в цикле занятого ожидания

repeat (* холостой ход *) until (time = 12:00:00);

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

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

новое время пробуждения = время начала ожидания + интервал

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

новое время пробуждения = время предыдущего пробуждения + интервал

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

wait until (ref time);

ref time := ref time -н 10 seconds;

время

ждать ждать ждать ждать

до момента до момента до момента до момента времениТ времени 2Т времени ЗТ времени AT

исполнение I исполнение 1 исполнение 1 исполнение I исполнение

время

Рис. 10.9. (а) Неправильный способ определения момента очередного запуска периодических задач - ошибка времени накапливается; (б) правильное решение - ошибка времени не накапливается

10.6.6. Внутренние подпрограммы операционной системы

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

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

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

завершения системной процедуры

(Результат возвращается вызывающей программе.




[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36] [37] [38] [39] [40] [41] [42] [43] [44] [45] [46] [47] [48] [49] [50] [51] [52] [53] [54] [55] [56] [57] [58] [59] [60] [61] [62] [63] [64] [65] [66] [67] [68] [69] [70] [71] [ 72 ] [73] [74] [75] [76] [77] [78] [79] [80] [81] [82] [83] [84] [85] [86] [87] [88] [89] [90]

0.0247