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

ЖАНРЫ

Linux программирование в примерах
Шрифт:

• Вызовы

getpid
и
getppid
возвращают ID текущего и родительского процессов соответственно. Родителем процесса, первоначальный родитель которого завершается, становится специальный процесс
init
с PID 1. Таким образом, PPID может меняться, и приложения должны быть готовы к этому.

• Системный вызов

nice
дает возможность настраивать приоритет вашего процесса. Чем приятнее вы по отношению к другим процессам, тем меньше ваш относительный приоритет, и наоборот. Лишь суперпользователь может иметь больший приоритет по сравнению с другими процессами. На современных системах, особенно однопользовательских, нет действительных причин для изменения знамения относительного приоритета.

• Системный вызов

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

• Значение

argv[0]
для новой программы обычно происходит от имени исполняемого файла, но это лишь соглашение. Как и в случае с
fork
, значительный, но не идентичный набор атрибутов наследуется через
exec
. Другие атрибуты сбрасываются для использования подходящих значений по умолчанию.

• Функция

atexit
регистрирует функции обратного вызова для вызова в порядке LIFO при завершении программы. Функции
exit
,
_exit
и
_Exit
все завершают программу, передавая статус завершения обратно родителю,
exit
очищает открытые потоки
FILE*
и запускает функции, зарегистрированные с помощью
atexit
. Две другие функции завершаются немедленно и должны использоваться, лишь когда
exec
в порожденном процессе завершилась неудачей. Возвращение из
main
подобно вызову
exit
с данным возвращаемым значением. В C99 и C++ выпадение из
main
в конце функции дает тот же результат, что и '
exit(0)
', но является плохой практикой.

• 

wait
и
waitpid
являются функциями POSIX для получения статуса завершения порожденного процесса. Различные макросы позволяют определить, завершился ли порожденный процесс нормально, и в таком случае определить статус его завершения, или же порожденный процесс претерпел сигнал завершения, и в этом случае определить совершивший этот проступок сигнал. Со специальными опциями
waitpid
предоставляет также сведения о потомках, которые не завершились, но изменили состояние.

• Системы GNU/Linux и большинство Unix-систем поддерживают также функции BSD

wait3
и
wait4
. GNU/Linux поддерживает также выходящий из употребления
union wait
. Функции BSD предоставляют
struct rusage
, давая доступ к сведениям об использовании времени процессора, что может быть удобным. Хотя если
waitpid
будет достаточной, то это наиболее переносимый способ выполнения.

• Группы процессов являются частью более крупного механизма управления заданиями, который включает сигналы, сеансы и манипулирование состоянием терминала,

getpgrp
возвращает ID группы процессов текущего процесса, a
getpgid
возвращает PGID определенного процесса. Сходным образом,
setpgrp
устанавливает PGID текущего процесса равным его PID, делая его лидером группы процессов;
setpgid
дает возможность родительскому процессу установить PGID порожденного, который еще не выполнил
exec
.

• Каналы и FIFO предоставляют односторонний коммуникационный канал между двумя процессами. Каналы должны быть установлены общим предком, тогда как FIFO могут использоваться любыми двумя процессами. Каналы создаются с помощью

pipe
, а файлы FIFO создаются с помощью
mkfifo
. Каналы и FIFO буферируют свои данные, останавливая производителя или потребителя, когда канал заполняется или пустеет.

• 

dup
и
dup2
создают копии дескрипторов открытых файлов. В сочетании с
close
они дают возможность поместить дескрипторы файлов на место стандартного ввода и вывода для каналов. Чтобы каналы работали правильно, все копии неиспользуемых концов каналов до исполнения программой назначения exec должны быть закрыты. Для создания нелинейных каналов может быть использован
/dev/fd
, что демонстрируется возможностью замещения процессов оболочками Bash и Korn.

• 

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

 • Дублирования дескриптора файла, имитирования

dup
и почти имитирования
dup2
.

 • Получения и установки флага close-on-exec. Флаг close-on-exec является в настоящее время единственным атрибутом дескриптора файла, но он важен. Он не копируется в результате действия

dup
, но должен явным образом устанавливаться для дескрипторов файлов, которые не должны оставаться открытыми после выполнения exec. На практике, это должно быть сделано для большинства дескрипторов файла.

 • Получение и установка флагов, управляющих нижележащим файлом. Из них

O_NONBLOCK
является, пожалуй, наиболее полезным, по крайней мере, для FIFO и каналов. Это определенно самый сложный флаг.

Упражнения

1. Напишите программу, которая выводит как можно больше сведений о текущем процессе: PID, PPID, открытые файлы, текущий каталог, значение относительного приоритета и т.д. Как вы можете сказать, какие файлы открыты? Если несколько дескрипторов файлов ссылаются на один и тот же файл, укажите это. (Опять-таки, как вы можете это узнать?)

2. Как вы думаете,

atexit
хранит указатели на функции обратного вызова? Реализуйте
atexit
, держа в уме принцип GNU «никаких произвольных ограничений». Набросайте схему (псевдокод) для
exit
. Каких сведений (внутренностей библиотеки
<stdio.h>
) вам не хватает, чтобы написать
exit
?

3. Программа

xargs
предназначена для многократных запусков команды и аргументов, когда аргументов слишком много для непосредственного набора в командной строке. Программа работает, считывая строки из стандартного ввода, рассматривая каждую строку в качестве отдельного аргумента для указанной команды, и упаковывая аргументы до тех пор, пока они остаются в пределах максимально допустимого для системы. Например:

$ grep ARG_MAX /usr/include/*.h /usr/include/*/*.h /* Командная строка */

bash: /bin/grep: Argument list too long /* Сообщение оболочки об ошибке */

$ find /usr/include -name '*.h' | xargs grep ARG_MAX /* find b xargs работают */

/usr/include/sys/param.h:#define NCARGS ARG_MAX

...

Константа

ARG_MAX
в
<limits.h>
представляет сочетание общей памяти, используемой средой, и аргументов командной строки. Стандарт POSIX не говорит, включает ли это массивы указателей или просто сами строки.

Напишите простую версию

xargs
, которая работает указанным способом. Не забудьте об окружении при вычислении размера необходимого пространства. Убедитесь, что тщательно управляете памятью.

4. Компоновка значения status, заполняемого функциями

wait
и
waitpid
, стандартом POSIX не определяется. Хотя и историческое, это 16-разрядное значение, которое выглядит, как показано на рис. 9.8.

Рис. 9.8. Компоновка значения status функции

wait

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