21728 21727 ps -e -o pid,ppid,command
Заметьте: родительский идентификатор команды ps
, 21727, соответствует интерпретатору bash
, из которого была вызвана команда. В свою очередь, родительский идентификатор интерпретатора, 21725, принадлежит программе xterm
— эмулятору терминала, в котором выполняется интерпретатор.
3.1.3. Уничтожение процесса
Для уничтожения процесса предназначена команда kill
. Ей достаточно указать идентификатор требуемого процесса.
Команда kill
посылает процессу сигнал SIGTERM
, являющийся запросом на завершение. [10] Команда kill позволяет посылать процессам и другие сигналы. Об этом рассказывается в разделе 3.4, "Завершение процесса".
По умолчанию, если в программе отсутствует обработчик данного сигнала, процесс просто завершает свою работу. О сигналах речь пойдет в разделе 3.3, "Сигналы".
Существуют два способа создания процессов. Первый из них относительно прост, но применяется редко, поскольку неэффективен и связан со значительным риском для безопасности системы. Второй способ сложнее, но избавлен от недостатков первого.
Функция system()
определена в стандартной библиотеке языка С и позволяет вызывать из программы системную команду, как если бы она была набрана в командной строке. По сути, эта функция запускает стандартный интерпретатор Bourne shell ( /bin/sh
) и передает ему команду на выполнение. Например, программа, представленная в листинге 3.2, вызывает команду ls -l /
, отображающую содержимое корневого каталога.
Листинг 3.2. ( system.c ) Использование функции system()
#include
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
— только в дочернем.
Читать дальше