Здавалка
Главная | Обратная связь

Завершение процесса

Операции над процессами

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

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

- инициализация системы;

- осуществление работающим потоком системного вызова создания нового процесса;

- запрос пользователя на создание нового процесса;

- запуск пакетного задания.

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

- создать дескриптор процесса и поместить его в таблицу процессов;

- создать виртуальное адресное пространство процесса и сформировать его структуру (например, скопировав структуру родительского процесса или проанализировав файл запускаемой программы);

- заполнить необходимыми данными виртуальное адресное пространство процесса (разместить в нем код, данные и т.д.);

- выделить процессу ресурсы, которые он может использовать сразу после создания (например, стандартный ввод-вывод) и проинициализировать их состояние;

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

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

- создать первичный поток процесса (данный процесс мы рассмотрим чуть позже).

Например, в UNIX существует системный запрос, направленный на создание нового процесса – fork(). Он создает новый процесс, который является почти точной копией родителя. После возвращения из системного вызова оба процесса выполняют инструкции одной и той же программы, имеют одинаковое содержимое адресного пространства и возобновляют выполнение с команды, следующей за системным вызовом (рассматривается случай однопоточного процесса). Однако между родительским и дочерним процессом имеется ряд различий:

- дочернему процессу присваивается уникальный идентификатор процесса PID, отличный от родительского;

- дескриптор процесса в UNIX содержит поле «идентификатор родительского процесса» PPID, соответственно, у дочернего процесса он устанавливается в PID родителя;

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

- для дочернего процесса очищаются все ожидающие доставки сигналы;

- временная статистика дочернего процесса обнуляется;

- блокировки памяти и записей, установленные родителем, потомком не наследуются;

- системный вызов fork() в родительском процессе возвращает PID дочернего процесса, а в дочернем – 0.

Для загрузки новой программы, процесс должен выполнить системный вызов семейства exec(). При этом новый процесс не порождается, сегменты кода, данных и стека создаются заново и инициализируются в соответствии с содержимым запускаемой программы, и окружение во многом сохраняется. Например, сохраняются назначения стандартных потоков ввода-вывода и приоритет процесса.

Рис. 9 Создание нового процесса в UNIX

В Windows вызов одной из функции CreateProcess() или CreateProcessEx() интерфейса Win32 управляет и созданием процесса и запуском в нем нужной программы.

Завершение процесса

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

- обычный выход - основной поток процесса совершил обычный выход или один из потоков совершил выход посредством обращения к соответствующему системному вызову;

- один из потоков совершил выход по ошибке (запланированный выход);

- один из потоков допустил неисправимую ошибку (незапланированный выход);

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

В основном процессы завершаются по мере выполнения своей работы. В UNIX для этого может использоваться системный вызов exit() (или _exit()), в Windows – ExitProcess().

Примером выхода по ошибке может служить поведение программы, которой передали неверный параметр командной строки.

Неисправимая ошибка возникает, когда процесс нарушает «правила поведения», предписанные в данной операционной системе пользовательским процессам, например, пытается выполнить операции чтения-записи по недоступным ему адресам памяти.

При наличии у процесса соответствующих привилегий, его потоки могут выполнять системные вызовы, завершающие другие процессы. В UNIX для этого может использоваться системный вызов kill(), в Windows – функция Win32 TerminateProcess().

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

- завершает выполнение всех потоков процесса;

- сохраняет статистические данные процесса и код возврата в его дескрипторе;

- переводит все ресурсы, принадлежащие процессу в непротиворечивое и стабильное состояние (например, закрывает все файлы);

- освобождает все ресурсы, принадлежавшие или использовавшиеся процессом;

- освобождает виртуальное адресное пространство процесса и уничтожает его;

- оповещает подсистемы, принимающие участие в управлении процессами, о завершении процесса с целью корректировки ими его дескриптора;

- состояние процесса устанавливает в значение «завершен».

В результате перечисленных действий от процесса остается только дескриптор в таблице дескрипторов ядра. Время его уничтожения в различных операционных системах определяется по-разному. В UNIX уничтожение дескриптора обычно производит родитель процесса с помощью системного вызова семейства wait() (при завершении любого процесса UNIX для его потомков родительским назначается всегда существующий процесс init). В Windows дескриптор процесса удаляется автоматически, когда счетчик его пользователей достигнет нуля.





©2015 arhivinfo.ru Все права принадлежат авторам размещенных материалов.