Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Системы реального времени.-6.pdf
Скачиваний:
27
Добавлен:
05.02.2023
Размер:
2.18 Mб
Скачать

5. АДМИНИСТРАТОР ПРОЦЕССОВ ОС QNX

5.1. Создание процессов

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

Функциями, используемыми ОС QNX для запуска других процессов, являются:

system();

fork();

vfork();

exec();

spawn().

Вид применяемой функции зависит от двух требований: переносимости и функциональности.

System() — самая простая функция. Она получает на вход одну командную строку, такую же, которую вы набрали бы в ответ на подсказку командного интерпретатора, и выполняет ее. Фактически, для обработки команды функция system() запускает копию командного интерпретатора.

Fork()порождает процесс, являющийся точной копией порождающего процесса. Новый процесс выполняется в том же

88

адресном пространстве и наследует все данные порождающего процесса.

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

Пример использования функции fork():

printf(“PID родителя равен %d\n”, getpid()); if (child_pid = fork()) {

printf(“Это родитель, PID сына %d\n”, child_pid);

} else {

printf(“Это сын, PID %d\n”, getpid());

}

Vfork() также порождает процесс. В отличие от функции fork(), позволяет существенно сэкономить на ресурсах, поскольку она формирует разделяемое адресное пространство родителя. Функция vfork() создает дочерний процесс, а затем приостанавливает родительский до тех пор, пока дочерний процесс не вызовет функцию exec() или не завершится.

Exec() заменяет образ порождающего процесса образом нового процесса. Возврата управления из нормально отработавшего exec() не существует, так как образ нового процесса накладывается на образ порождающего процесса. В системах стандарта POSIX новые процессы обычно создаются без возврата управления порождающему процессу — сначала вызывается fork(), а затем из порожденного процесса — exec().

Spawn()создает новый процесс по принципу «отец–сын». Это позволяет избежать использования примитивов fork()и exec(), что ускоряет обработку и является более эффективным средством создания новых процессов. В отличие от fork() и exec(), которые по определению создают процесс на том же узле, что и порождающий процесс, примитив spawn()может создавать процессы на любом узле сети.

89

Функции fork() и exec() определены стандартом POSIX, а функция spawn() реализована только в QNX.

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

Таблица 5.1 Возможности наследования при создании процесса

Наследуемый параметры

fork()

exec()

spawn()

Идентификатор процесса

Нет

Да

Нет

Открытые файлы

Да

На выбор

На выбор

Блокировка файлов

Нет

Да

Нет

Задержанные сигналы

Нет

Да

Нет

Маска сигнала

Да

На выбор

На выбор

Игнорируемые сигналы

Да

На выбор

На выбор

Обработчик сигналов

Да

Нет

Нет

Переменные среды

Да

На выбор

На выбор

Идентификатор сеанса

Да

Да

На выбор

Группа процесса

Да

Да

На выбор

Реальные идентификаторы груп-

Да

Да

Да

пы и пользователя ( UID, GID )

 

 

 

Эффективные UID, GID

Да

На выбор

На выбор

Текущий рабочий каталог

Да

На выбор

На выбор

Маска создания файлов

Да

Да

Да

Приоритет

Да

На выбор

На выбор

Метод планирования

Да

На выбор

На выбор

Виртуальные каналы

Нет

Нет

Нет

Символические имена

Нет

Нет

Нет

Таймеры реального времени

Нет

Нет

Нет

Каждый процесс проходит четыре фазы:

1)создание процесса, заключающееся в присвоении идентификатора процесса ID новому процессу и задании информации, определяющей его программную среду. Большая часть этой информации наследуется от «родителя» нового процесса;

2)загрузка образов процессов, выполняемая загрузчиком

«по цепочке». Загрузчик входит в состав администратора процессов и выполняется под идентификатором нового процесса.

90

Это позволяет администратору процессов выполнять другие запросы при загрузке программ;

3)выполнение процесса, начинающееся после загрузки программного кода. Процесс начинает конкурировать с другими процессами, стремясь получить ресурсы центрального процессора. Обратите внимание: процессы выполняются конкурентно вместе со своими «родителями». Кроме того, гибель «родителя» не вызывает автоматически гибель порожденных им процессов;

4)завершение процесса, осуществляемое одним из способов:

по сигналу, определяющему процесс завершения;

при возврате управления по функции exit()— явно, либо по функции main()— по умолчанию.

Завершение включает в себя две стадии.

1. Администратор процессов инициирует выполнение программы завершения «по цепочке». Программа завершения входит

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

все виртуальные каналы, которые имел процесс;

вся память, выделенная процессу;

все символические имена;

все номера основных устройств (только для администраторов ввода/вывода);

все обработчики прерываний;

все proxy;

все таймеры.

2. После запуска программы завершения к породившему ее процессу посылается уведомление о завершении порожденного процесса. Эта стадия выполняется внутри администратора процессов.

Если породивший процесс не выдал wait()или waitpid(), то порожденный процесс становится так называемым «зомбипроцессом» и не завершается до тех пор, пока породивший процесс не выдаст wait() или не завершится сам.

Для того чтобы не ждать завершения порожденного процесса, следует либо установить признак _SPAWN_NOZOMBIE в функ-

91