Студопедия  
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

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

Читайте также:
  1. II Разновидности производственных процессов
  2. II. Речевая деятельность человека. Создание текста. Коммуникативные качества хорошей речи и способы их достижения
  3. II. Сравнение потоков и процессов
  4. III Принципы организации производственных процессов
  5. III. Завершение
  6. IV. Закрепление полученного материала и завершение занятия
  7. O Подвижность нервных процессов
  8. А) создание Лиги Наций
  9. А. Создание Правил эксплуатации и назначение ответственных за их соблюдение
  10. Анализ существующих процессов проектирования

Новые процессы создаются при помощи функции fork() (см. в следующем примере).

#include <unistd.h>pid_t fork (void);

Листинг 7.20. Описание функции fork().

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

  1. У порожденного процесса свой идентификатор, равно как и идентификатор родительского процесса.
  2. У порожденного процесса собственная копия файловых дескрипторов, ссылающихся на те же описания открытых файлов, что и соответствующие дескрипторы родительского процесса.
  3. Порожденный процесс не наследует блокировки файлов, установленные родительским процессом.
  4. Порожденный процесс создается с одним потоком управления – копией того, что вызвал fork().
  5. Имеются также некоторые тонкости, связанные с обработкой сигналов, на которых мы, однако, останавливаться не будем.

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

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

Напомним, что заголовок функции main() C-программы выглядит в общем случае так, как показано в в следующем примере.

int main (int argc, char *argv []);

Пример 7.21. Заголовок функции main() C-программы.

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

Аналогичный смысл имеют аргументы функций семейства exec() (см. в следующем примере).

#include <unistd.h>extern char **environ;int execl (const char *path, const char *arg0,... /*, (char *) 0 */);int execv (const char *path, char *const argv []);int execle (const char *path, const char *arg0,... /*, (char *) 0, char *const envp [] */);int execve (const char *path, char *const argv [], char *const envp []);int execlp (const char *file, const char *arg0,... /*, (char *) 0 */);int execvp (const char *file, char *const argv []);

Пример 7.22. Описание функций семейства exec().

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

Переменная environ инициализируется как указатель на массив указателей на составляющие окружение цепочки символов. Массивы argv и environ завершаются пустым указателем.

Аргумент path указывает на маршрутное имя файла с новым образом процесса.

Аргумент file имеет аналогичный смысл, однако, если он задан как простое имя, то производится поиск в каталогах, заданных переменной окружения PATH.

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

Аргумент envp имеет тот же смысл и назначение, что и переменная environ.

Файловые дескрипторы остаются открытыми в новом образе, если только они не были снабжены флагом FD_CLOEXEC.

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

Следующие атрибуты процесса остаются неизменными:

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

#include <sys/wait.h>pid_t wait (int *stat_loc);pid_t waitpid (pid_t pid, int *stat_loc, int options);

Пример 7.23. Описание функций семейства wait().

Функция waitpid() эквивалентна wait(), если аргумент pid равен (pid_t) (-1), а аргумент options имеет нулевое значение. Аргумент pid задает набор порожденных процессов, статус завершения которых запрашивается. Значение (pid_t) (-1) представляет произвольный элемент множества порожденных процессов. Если pid > 0>, имеется в виду один процесс с данным идентификатором. Нулевое значение специфицирует любого потомка из той же группы процессов, что и вызывающий. Наконец, при pid < (pid_t) (-1) запрашивается статус завершения любого порожденного процесса из группы, идентификатор которой равен абсолютной величине pid.

Аргумент options задается как побитное ИЛИ следующих флагов, определенных в заголовочном файле <sys/wait.h>.

WNOHANG

Функция waitpid() не приостанавливает выполнение вызывающего потока управления, если запрашиваемый статус не доступен немедленно.

WUNTRACED

Наряду со статусом завершения запрашивать статус остановленных, но еще не опрошенных процессов.

Если запрос статуса порожденного процесса завершился успешно, функции wait() и waitpid() возвращают идентификатор этого процесса и размещают по указателю stat_loc (если он отличен от NULL) значение, которое будет нулевым тогда и только тогда, когда выдан статус порожденного процесса, завершившегося по одной из трех причин:

Для анализа целочисленного значения stat_val, на которое указывает аргумент stat_loc, в файле <sys/wait.h> определен набор макросов. Например, значение WIFEXITED (stat_val) будет ненулевым в случае нормального завершения порожденного процесса; при этом WEXITSTATUS (stat_val) возвращает младший байт статуса. Макрос WIFSTOPPED (stat_val) возвращает ненулевое значение, если получен статус останов- ленного процесса.

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

#include <stdlib.h>void exit (int status);void _Exit (int status);#include <unistd.h>void _exit (int status);

Пример 7.24. Описание функций семейства exit().

Значением аргумента status могут служить константы 0, EXIT_SUCCESS, EXIT_FAILURE или любое другое значение, хотя ожидающему родительскому процессу будет доступен только младший байт статуса (status & 0377).

Функция exit(), в отличие от _Exit() и _exit(), производит аккуратное завершение: выполняет зарегистрированные функции (см. ниже описание функции atexit()), выталкивает буфера, закрывает потоки, удаляет временные файлы и т.д. Функции _Exit() и _exit() эквивалентны. Все функции семейства exit() закрывают файловые дескрипторы, открытые вызывающим процессом.

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

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

Функция atexit() (см. в следующем примере) позволяет зарегистрировать функции, которые будут вызываться, если процесс завершается, обращаясь к exit() или возвращаясь из main().

#include <stdlib.h>int atexit (void (*func) (void));

Пример 7.25. Описание функции atexit().

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

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

#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <sys/wait.h> static void atefunc (void) {/* Перед завершением выдадим информацию о *//* процессах */printf ("Ситуация перед завершениемродительского процесса\n");(void) system ("ps -o pid,ppid,vsz,args");} int main (void) { int pid; int stat; /* Отменим буферизацию стандартного вывода */ setbuf (stdout, NULL); /* Зарегистрируем обработчик завершения процесса */ if (atexit (atefunc)!= 0) { perror ("ATEXIT"); exit (1); } /* Создадим новый процесс */ if ((pid = fork ()) < 0) { perror ("FORK"); exit (2); } else if (pid == 0) { /* Порожденный процесс */ /* Выполним служебную программу ps */ printf ("Ситуация с точки зрения порожденного процесса\n"); (void) execl ("/bin/ps", "ps", "-o", "pid,ppid,args", (char *) 0); perror ("EXEC"); exit (3); /* execl() завершился неудачей */ } else { /* Родительский процесс */ sleep (1); /* Вероятно, порожденный процесс уже */ /* завершился */ /* Посмотрим на текущую ситуацию */ printf ("Ситуация перед вызовом waitpid() в родительском процессе\n"); (void) system ("ps -o pid,ppid,vsz,args"); (void) waitpid (pid, &stat, 0); printf ("Статус завершения порожденного процесса с идентификатором %d: %d\n", pid, stat); } return 0;}

Пример 7.26. Пример использования функций порождения и завершения процессов.

Результат работы этой программы может выглядеть так, как показано в в следующем примере (выполнимый файл программы имеет имя prog30).

Ситуация с точки зрения порожденного процессаPID PPID COMMAND6123 1072 -sh29568 6123 prog3029569 29568 ps -o pid,ppid,argsСитуация перед вызовом waitpid() в родительском процессеPID PPID VSZ COMMAND6123 1072 2260 -sh29568 6123 1340 prog3029569 29568 0 [ps <defunct>]29570 29568 2584 ps -o pid,ppid,vsz,argsСтатус завершения порожденного процесса с идентификатором 29569: 0Ситуация перед завершением родительского процессаPID PPID VSZ COMMAND6123 1072 2260 -sh29568 6123 1340 prog3029571 29568 2584 ps -o pid,ppid,vsz,args

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

Обратим внимание на информацию о зомби-процессе (с пометкой <defunct>), а также на то, что функция, зарегистрированная с помощью atexit(), вызвана в результате возврата из main().




Дата добавления: 2014-12-19; просмотров: 26 | Поможем написать вашу работу | Нарушение авторских прав




lektsii.net - Лекции.Нет - 2014-2024 год. (0.008 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав