Назад

Содержание

Вперед


1.5. Процессы.

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

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

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

    Здесь argv - массив указателей на строки, содержащие параметры, переданные задаче при запуске, argc - число элементов массива argv, envir - массив строк, содержащих переменные среды (environment) и их значения.

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

    Во время выполнения задача может запустить другой процесс. Для этого в системе UNIX предусмотрена системная функция fork( ):

#include <sys/types.h>
#include <unistd.h>

pid_t fork (void);

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

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

#include <unistd.h>

int exec ( const char *path, int argc, char *argv[ ] );

    Здесь path - имя выполняемого файла, argv - массив указателей на строки, передаваемые загружаемой программе в качестве параметров, argc - количество строк массива argv. Прототипы и объяснение других процедур, подобных exec( ), можно найти в соответствующих разделах подсказки UNIX (см. подробнее 1.9.1.).

    Процесс-"родитель", когда заканчивает работу, может подождать завершения запущенных им ранее программ. Для этого следует обратиться к системной процедуре wait( ):

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait (int *status);

    Функция возвращает идентификатор процесса, окончившего работу. Код его завершения записывается по адресу, заданному аргументом status.

    Заметим, что в различных диалектах UNIX имеются более развитые варианты функции wait( ). Это wait3( ), waitpid( ), waitid( ) (более подробную информацию можно найти в документации по той системе, на которой работает пользователь).

    В качестве примера рассмотрим подпрограмму, реализующую функцию system( ). Она выполняет переданную ей командную строку при помощи интерпретатора командного языка (командного процессора) sh.

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int system (const char *cmd_string)
  {
  pid_t pid;
  int status;
  if (cmd_string = = NULL)
    return (1);
  if ( (pid = fork ( ) ) < 0)
    return (-1);
  if (pid == 0) {   /* процесс-"потомок" */
    execl ("/bin/sh", "sh", "-c", cmd_string, (char*) 0);
    exit (-1);     /* выполняется при ошибке в execl */
  }
  else {     /* процесс-"родитель" ожидает завершения */
             /* выполнения процесса-"потомка" */
  wait (&status);
  }
}