Реферат: Основные понятия и программное обеспечение систем реального времени
1. Как правило, потоки не могут быть подгружены динамически. Чтобы добавить новый поток, необходимо провести соответствующие изменения в исходных текстах и перекомпилировать приложение. Процессы, в отличие от потоков, подгружаемы, что позволяет динамически изменять функции системы в процессе ее работы. Кроме того, так как процессам соответствуют отдельные программные модули, они могут быть разработаны различными компаниями, чем достигается дополнительная гибкость и возможность использования ранее наработанного ПО.
2. То, что потоки имеют доступ к областям данных друг друга, может привести к ситуации, когда некорректно работающий поток способен испортить данные другого потока. В отличие от этого процессы защищены от взаимного влияния, а попытка записи в «не свою» память приводит, как правило, к возникновению специального прерывания по обработке «исключительных ситуаций». Реализация механизмов управления процессами и потоками, возможность их взаимного сосуществования и взаимодействия определяются конкретным ПО РВ.
3.2. Основные свойства задач
Как правило, вся важная, с точки зрения операционной системы, информация о задаче хранится в унифицированной структуре данных управляющем блоке (Task Control Block, TCB). В блоке хранятся такие параметры, как имя и номер задачи, верхняя и нижняя границы стека, ссылка на очередь сообщений, статус задачи, приоритет и т. п.
Приоритет – это некое целое число, присваиваемое задаче и характеризующее ее важность по сравнению с другими задачами, выполняемыми в системе. Приоритет используется в основном планировщиком задач для определения того, какая из готовых к работе задач должна получить управление. Различают системы с динамической и статической приоритетностью. В первом случае приоритет задач может меняться в процессе исполнения, в то время как во втором приоритет задач жестко задается на этапе разработки или во время начального конфигурирования системы.
Контекст задачи – это набор данных, содержащий всю необходимую информацию для возобновления выполнения задачи с того места, где она была ранее прервана. Часто контекст хранится в ТСВ и включает в себя такие данные, как счетчик команд, указатель стека, регистры СРU и FPU и т. п. Планировщик задач в случае необходимости сохраняет контекст текущей активной задачи и восстанавливает контекст задачи, назначенной к исполнению. Такое переключение контекстов и является, по сути, основным механизмом ОС РВ при переходе от выполнения одной задачи к выполнению другой.
Состояние (статус) задачи . С точки зрения операционной системы, задача может находиться в нескольких состояниях. Число и название этих состояний различаются от одной ОС к другой. По-видимому, наибольшее число состояний задачи определено в языке Ada. Тем не менее практически в любой ОС РВ загруженная на выполнение задача может находиться, по крайней мере, в трех состояниях.
1. Активная задача – это задача, выполняемая системой в текущей момент времени.
2. Готовая задача – это задача, готовая к выполнению и ожидающая у планировщика своей «очереди».
3. Блокированная задача – это задача, выполнение которой приостановлено до наступления определенных событий. Такими событиями могут быть освобождение необходимого задаче ресурса, поступление ожидаемого сообщения, завершение интервала ожидания и т. п.
Пустая задача (Idle Task) – это задача, запускаемая самой операционной системой в момент инициализации и выполняемая только тогда, когда в системе нет других готовых для выполнения задач. Пустая задача запускается с самым низким приоритетом и, как правило, представляет собой бесконечный цикл «ничего не делать». Наличие пустой задачи предоставляет операционной системе удобный механизм отработки ситуаций, когда нет ни одной готовой к выполнению задачи.
Многократный запуск задач . Как правило, многозадачные ОС позволяют запускать несколько копий одной и той же задачи. При этом для каждой такой копии создается свой ТСВ и выделяется своя область памяти. В целях экономии памяти может быть предусмотрено совместное использование одного и того же исполняемого кода для всех запущенных копий. В этом случае программа должна обеспечивать повторную входимость (реентерабельность). Кроме того, программа не должна использовать временные файлы с фиксированными именами и должна корректно осуществлять доступ к глобальным ресурсам.
Реентерабельность (повторная входимость) означает возможность без негативных последствий временно прервать выполнение какой-либо функции или подпрограммы, а затем вызвать эту функцию или подпрограмму снова. Частным проявлением реентерабельности является рекурсия, когда тело подпрограммы содержит вызов самой себя. Классическим примером нереентерабельной системы является DOS, а типичной причиной нереентерабельности служит использование глобальных переменных. Предположим, что у нас есть функция, реализующая низкоуровневую запись на диск, и пусть она использует глобальную переменную write_sector, которая устанавливается в соответствии с параметром, передаваемым этой функции при вызове. Предположим теперь, что Задача А вызывает эту функцию с параметром 3, то есть хочет записать данные в сектор номер 3. Допустим, что когда переменная write_sector уже равна 3, но сама запись еще не произведена, выполнение Задачи А прерывается и начинает выполняться Задача В, котораявызывает ту же функцию, но с аргументом 10. После того как запись в сектор номер 10 будет произведена, управление рано или поздно вернется к Задаче А, которая продолжит работу с того же места. Однако, так как переменная write_sector имеет теперь значение 10, данные Задачи А, предназначавшиеся для сектора номер 3, будут вместо этого записаны в сектор номер 10. Из приведенного примера видно, что ошибки, связанные с нереентерабельностью, трудно обнаружить, а последствия они могут вызвать самые катастрофические.
3.3. Планирование задач
Важной частью любой ОС РВ является планировщик задач. Несмотря на то, что в разных источниках он может называться по-разному (диспетчер задач, супервизор и т. п.), его функции остаются теми же: определить, какая из задач должна выполняться в системе в каждый конкретный момент времени. Самым простым методом планирования, не требующим никакого специального ПО и планировщика как такового, является использование циклического алгоритма в стиле round robin:
void main (void)
{
for (;;) {
task0();
task1();
task2();
/* и т. д. */
}
}
Каждая «задача», представляющая собой отдельную подпрограмму, выполняется циклически. При этом надо придерживаться следующих правил:
1. Подпрограммы не должны содержать циклов ожидания в стиле
while (TRUE) {
if (switch_up()) {
lamp_off();