В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Процессы
Создание и завершение процессов
Новые процессы создаются при помощи функции fork() (см. листинг 7.20).
#include <unistd.h> pid_t fork (void);Листинг 7.20. Описание функции fork().
Новый (порожденный) процесс является точной копией процесса, вызвавшего fork() (родительского), за исключением следующих моментов.
- У порожденного процесса свой идентификатор, равно как и идентификатор родительского процесса.
- У порожденного процесса собственная копия файловых дескрипторов, ссылающихся на те же описания открытых файлов, что и соответствующие дескрипторы родительского процесса.
- Порожденный процесс не наследует блокировки файлов, установленные родительским процессом.
- Порожденный процесс создается с одним потоком управления – копией того, что вызвал fork().
- Имеются также некоторые тонкости, связанные с обработкой сигналов, на которых мы, однако, останавливаться не будем.
В случае успешного завершения функция fork() возвращает порожденному процессу 0, а родительскому процессу – идентификатор порожденного процесса. После этого оба процесса начинают независимо выполнять инструкции, расположенные за обращением к fork(). При неудаче родительскому процессу возвращается -1, новый процесс не создается.
Поскольку возвращаемые функцией fork() значения различны для обеих копий, родительский и порожденный процессы могут далее выполняться по-разному. Например, процесс-предок переходит в состояние ожидания завершения процесса-потомка либо, если процесс-потомок запущен асинхронно, продолжает выполнение параллельно с ним. Процесс-потомок при помощи функции семейства exec() подменяет программу, которая определяет поведение процесса, и передает ей управление и список аргументов.
Напомним, что заголовок функции main() C-программы выглядит в общем случае так, как показано в листинге 7.21.
int main (int argc, char *argv []);7.21. Заголовок функции main() C-программы.
Значение argc равно количеству аргументов; argv – это массив указателей собственно на аргументы, которые определяются исходя из командной строки, запускающей C-программу. В соответствии с принятым соглашением, значение argc не меньше единицы, а первый элемент массива argv указывает на цепочку символов, содержащую имя выполняемого файла.
Аналогичный смысл имеют аргументы функций семейства exec() (см. листинг 7.22).
#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() (см. листинг 7.23). Если информация о статусе завершения была доступна до вызова 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.