Чтение онлайн

ЖАНРЫ

Программирование для Linux. Профессиональный подход

Самьюэл Алекс

Шрифт:

Ниже приведено несколько первых и последних строк, выдаваемых этой командой в нашей системе:

% ps -e -о pid,ppid,command

PID PPID COMMAND

1 0 init [5]

2 1 [kflushd]

3 1 [kupdate]

...

21725 21693 xterm

21727 21725 bash

21728 21727 ps -e -o pid,ppid,command

Заметьте: родительский идентификатор команды

ps
, 21727, соответствует интерпретатору
bash
, из которого была вызвана команда. В свою очередь, родительский идентификатор интерпретатора, 21725, принадлежит программе
xterm
 — эмулятору
терминала, в котором выполняется интерпретатор.

3.1.3. Уничтожение процесса

Для уничтожения процесса предназначена команда

kill
. Ей достаточно указать идентификатор требуемого процесса.

Команда

kill
посылает процессу сигнал
SIGTERM
, являющийся запросом на завершение. [10] По умолчанию, если в программе отсутствует обработчик данного сигнала, процесс просто завершает свою работу. О сигналах речь пойдет в разделе 3.3, "Сигналы".

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

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

10

Команда

kill
позволяет посылать процессам и другие сигналы. Об этом рассказывается в разделе 3.4, "Завершение процесса".

3.2.1. Функция system

Функция

system
определена в стандартной библиотеке языка С и позволяет вызывать из программы системную команду, как если бы она была набрана в командной строке. По сути, эта функция запускает стандартный интерпретатор Bourne shell (
/bin/sh
) и передает ему команду на выполнение. Например, программа, представленная в листинге 3.2, вызывает команду
ls -l /
, отображающую содержимое корневого каталога.

Листинг 3.2. (system.c) Использование функции
system

#include <stdlib.h>

int main {

 int return_value;

 return_value = system("ls -l /");

 return return_value;

}

Функция

system
возвращает код завершения указанной команды. Если интерпретатор не может быть запущен, возвращается значение 127, а в случае возникновения других ошибок — -1.

Поскольку функция

system
запускает интерпретатор команд, она подвержена всем тем ограничениям безопасности, что и системный интерпретатор. Рассчитывать на наличие какой-то конкретной версии Bourne shell не приходится. В большинстве UNIX-систем программа
/bin/sh
представляет собой символическую ссылку на другой интерпретатор. В Linux — это
bash
(Bourne-Again SHell), причем в разных дистрибутивах присутствуют разные его версии. Вызов из функции
system
программы с привилегиями пользователя
root
также может иметь неодинаковые последствия в разных системах. Таким образом, лучше создавать процессы с помощью функций
fork
и
exec
.

3.2.2. Функции fork и exec

В DOS и Windows API имеется семейство функций

spawn
. Они принимают в качестве аргумента имя программы, создают новый экземпляр ее процесса и запускают его. В Linux нет функции, которая делала бы все это за один заход. Вместо этого имеется функция
fork
, создающая дочерний процесс, который является точной копией родительского процесса, и семейство функций
exec
, заставляющих требуемый процесс перестать быть экземпляром одной программы и превратиться в экземпляр другой программы. Чтобы создать новый процесс, нужно сначала с помощью функции
fork
создать копню текущего процесса, а затем с помощью функции
exec
преобразовать одну из копий в экземпляр запускаемой
программы.

Вызов функции fork

Вызывая функцию

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

Как же различить между собой оба процесса? Во-первых, дочерний процесс — это новый, только что появившийся в системе процесс, поэтому его идентификатор отличается от идентификатора родительского процесса. Таким образом, программа может вызвать функцию

getpid
и узнать, где именно она находится. Но сама функция
fork
реализует другой способ: она возвращает разные значения в родительском и дочернем процессах. Родительский процесс получает идентификатор своего потомка, а дочернему процессу возвращается 0. В системе нет процессов с нулевым идентификатором, так что программа легко разбирается в ситуации.

В листинге 3.3 приведен пример ветвления программы с помощью функции

fork
. Учтите, что первая часть инструкции
if
выполняется только в родительском процессе, тогда как ветвь
else
— только в дочернем.

Листинг 3.3. (fork.c) Ветвление программы с помощью функции
fork

#include <stdio.h>

#include <sys/types.h>

#include <unistd.h>

int main {

 pid_t child_pid;

 printf("The main program process ID is %d\n",

(int)getpid);

 child_pid = fork;

 if (child_pid != 0) {

printf("This is the parent process, with ID %d\n",

(int)getpid);

printf("The child's process ID is %d\n", (int)child_pid);

 } else

printf("This is the child process, with ID %d\n",

(int)getpid);

 return 0;

}

Семейство функций exec

Функции семейства

exec
заменяют программу, выполняющуюся в текущем процессе, другой программой. Когда программа вызывает функцию
exec
, ее выполнение немедленно прекращается и начинает работу новая программа.

Функции, входящие в семейство

exec
, немного отличаются друг от друга по своим возможностям и способу вызова.

■ Функции, в названии которых присутствует суффикс

'p'
(
execvp
и
execlp
), принимают в качестве аргумента имя программы и ищут эту программу в каталогах, определяемых переменном среды
PATH
. Всем остальным функциям нужно передавать полное путевое имя программы.

■ Функции, в названии которых присутствует суффикс

'v'
(
execv
,
execvp
и
execve
), принимают список аргументов программы в виде массива строковых указателей, оканчивающегося
NULL
– указателем. Функции с суффиксом
'l'
(
execl
,
execlp
и
execle
) принимают список аргументов переменного размера.

■ Функции, в названии которых присутствует суффикс

'e'
(
execve
и
execle
), в качестве дополнительного аргумента принимают массив переменных среды. Этот массив содержит строковые указатели и оканчивается пустым указателем. Каждая строка должна иметь вид
"ПЕРЕМЕННАЯ=значение"
.

Поскольку функция

exec
заменяет одну программу другой, она никогда не возвращает значение — только если вызов программы оказался невозможен в случае ошибки.

Поделиться с друзьями: