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

на главную - закладки

Жанры

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

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

Шрифт:

#include <unistd.h>

int main {

 pid_t child_pid;

 /* Создание дочернего процесса. */

 child_pid = fork;

 if (child_pid > 0) {

/* Это родительский процесс — делаем минутную паузу. */

sleep(60);

 } else {

/* Это дочерний процесс — немедленно завершаем работу. */

exit(0);

 }

 return 0;

}

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

% ps -е -o pid,ppid,stat,cmd

Эта команда отображает идентификатор самого процесса и его предка, а также статус процесса и его командную строку. Обратите внимание на присутствие двух процессов с именем

zombie
. Один из них — предок, другой — потомок. У последнего идентификатор родительского процесса равен идентификатору основного процесса
zombie
, при этом потомок обозначен как <defunct> (несуществующий), а его код состояния равен Z (т.е. zombie — зомби).

Итак, мы хотим узнать, что будет, когда программа

zombie
завершится, не вызвав функцию
wait
. Останется ли процесс-зомби? Нет — выполните команду
ps
и убедитесь в этом: оба процесса
zombie
исчезли. Дело в том, что после завершения программы управление ее дочерними процессами принимает на себя специальный процесс — демон
init
, который всегда работает, имея идентификатор 1 (это первый процесс, запускаемый при загрузке Linux). Демон
init
автоматически удаляет все унаследованные им дочерние процессы-зомби.

3.4.4. Асинхронное удаление дочерних процессов

Если дочерний процесс просто вызывает другую программу с помощью функции

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

Один подход заключается в периодическом вызове функции

wait3
или
wait4
. Функция
wait
в данной ситуации не подходит, так как в случае отсутствия завершившегося дочернего процесса она заблокирует основную программу. А вот упомянутые две функции принимают дополнительный флаг
WNOHANG
, переводящий их в неблокируемый режим, в котором функция либо удаляет дочерний процесс, если он есть, либо просто завершается. В первом случае возвращается идентификатор процесса, во втором — 0.

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

SIGCHLD
, посылаемым как раз тогда, когда завершается дочерний процесс. По умолчанию программа никак не реагирует на этот сигнал, поэтому раньше вы могли и не знать о его существовании.

Таким образом, нужно организовать удаление дочерних процессов в обработчике сигнала

SIGCHLD
. Естественно, код состояния удаляемого процесса следует сохранять в глобальной переменной, если эта информация необходима основной программе. В листинге 3.7 показана программа, в которой реализована данная методика.

Листинг 3.7. (sigchld.c) Удаление дочерних процессов в обработчике сигнала
SIGCHLD

#include <signal.h>

#include <string.h>

#include <sys/types.h>

#include <sys/wait.h>

sig_atomic_t child_exit_status;

void clean_up_child_process(int signal_number) {

 /* Удаление дочернего процесса. */

 int status;

 wait(&status);

 /* Сохраняем статус потомка в глобальной переменной. */

 child_exit_status = status;

}

int main {

 /* Обрабатываем сигнал SIGCHLD, вызывая функцию

clean_up_child_process. */

 struct sigaction sigchld_action;

 memset(&sigchld_action, 0, sizeof(sigchld_action));

 sigchld_action.sa_handler = &clean_up_child_process;

 sigaction(SIGCHLD, &sigchld_action, NULL);

 /* Далее выполняются основные действия, включая порождение

дочернего процесса. */

 /* ... */

 return 0;

}

Глава 4

Потоки

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

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

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

exec
, все остальные потоки завершаются (естественно, новая программа может создавать собственные потоки).

В Linux реализована библиотека API-функций работы с потоками, соответствующая стандарту POSIX (она называется Pthreads). Все функции и типы данных библиотеки объявлены в файле

<pthread.h>
. Эти функции не входят в стандартную библиотеку языка С, поэтому при компоновке программы нужно указывать опцию
– lpthread
в командной строке.

4.1. Создание потока

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

pthread_t
.

Поделиться:
Популярные книги

Кадет Морозов

Шелег Дмитрий Витальевич
4. Живой лёд
Фантастика:
боевая фантастика
5.72
рейтинг книги
Кадет Морозов

Царь царей

Билик Дмитрий Александрович
9. Бедовый
Фантастика:
фэнтези
мистика
5.00
рейтинг книги
Царь царей

Вернуть невесту. Ловушка для попаданки 2

Ардова Алиса
2. Вернуть невесту
Любовные романы:
любовно-фантастические романы
7.88
рейтинг книги
Вернуть невесту. Ловушка для попаданки 2

S-T-I-K-S. Пройти через туман

Елисеев Алексей Станиславович
Вселенная S-T-I-K-S
Фантастика:
боевая фантастика
7.00
рейтинг книги
S-T-I-K-S. Пройти через туман

Монстр из прошлого тысячелетия

Еслер Андрей
5. Соприкосновение миров
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Монстр из прошлого тысячелетия

Кодекс Крови. Книга ХII

Борзых М.
12. РОС: Кодекс Крови
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Кодекс Крови. Книга ХII

Автобиография

Твен Марк
Документальная литература:
биографии и мемуары
6.25
рейтинг книги
Автобиография

Вторая жизнь майора. Цикл

Сухинин Владимир Александрович
Вторая жизнь майора
Фантастика:
героическая фантастика
боевая фантастика
попаданцы
5.00
рейтинг книги
Вторая жизнь майора. Цикл

Воин-Врач

Дмитриев Олег
1. Воин-Врач
Фантастика:
попаданцы
альтернативная история
историческое фэнтези
6.00
рейтинг книги
Воин-Врач

Хроники Тириса. Книга 3

Маханенко Василий Михайлович
3. Хроники Тириса
Фантастика:
боевая фантастика
космическая фантастика
фантастика: прочее
5.00
рейтинг книги
Хроники Тириса. Книга 3

Запечатанный во тьме. Том 2

NikL
2. Хроники Арнея
Фантастика:
уся
эпическая фантастика
фэнтези
5.00
рейтинг книги
Запечатанный во тьме. Том 2

Эволюционер из трущоб

Панарин Антон
1. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб

Искатель 1

Шиленко Сергей
1. Валинор
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Искатель 1

Газлайтер. Том 1

Володин Григорий
1. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 1