3. Усовершенствуйте ch08-statvfs.c
, чтобы она не игнорировала смонтированные файловые системы NFS. Такие файловые системы имеют устройство в форме server.example.com:/big/disk
.
4. Измените ch08-statfs.c
(ту, которая использует специфичный для Linux вызов statfs()
), чтобы ее вывод был похож на вывод df
.
5. Добавьте опцию -i
к программе, которую вы написали для предыдущего упражнения, чтобы ее вывод был такой же, как у 'df -i
'.
6. Используя opendir()
, readdir()
, stat()
или fstat()
, dirfd()
и fchdir()
, напишите собственную версию getcwd()
. Как вы вычислите общий размер, который должен иметь буфер? Как вы будете перемещаться по иерархии каталогов?
7. Усовершенствуйте свою версию getcwd()
, чтобы она выделяла буфер для вызывающего, если первый аргумент равен NULL.
8. Можете ли вы использовать nftw()
для написания getcwd()
? Если нет, почему?
9. Используя nftw()
, напишите свою собственную версию chown
, которая принимает опцию -R
для рекурсивной обработки целых деревьев каталогов. Убедитесь, что без -R
, 'chown
'
10. Набор процедур BSD fts()
(«file tree stream» — «поток дерева файлов») предоставляет другой способ для обработки иерархии каталогов. У него несколько более тяжелый API как в смысле числа функций, так и структур, которые доступны для вызывающих функций уровня пользователя. Эти функции доступны как стандартная часть GLIBC.
Прочтите справочную страницу fts()
.
11. Посмотрите справочную страницу find
с самого начала, какой набор деревьев файлов вы бы предпочли, nftw()
или fts()
? Почему?
Часть 2
Процессы, IPC и интернационализация
Глава 9
Управление процессами и каналы
Как мы говорили в главе 1 «Введение», если бы нужно было резюмировать Unix (а следовательно, и Linux) в трёх словах, это были бы «файлы и процессы». Теперь, когда мы увидели, как работать с файлами и каталогами, время взглянуть на оставшуюся часть утверждения: процессы. В частности, мы исследуем, как создаются и управляются процессы, как они взаимодействуют с открытыми файлами и как они могут взаимодействовать друге другом. Последующие главы исследуют сигналы — грубый способ дать возможность одному процессу (или ядру) сообщить другому о том, что произошло некоторое событие — и проверку прав доступа.
В данной главе картина начинает усложняться. В частности, для полноты мы должны упомянуть о вещах, которые не будут рассматриваться до конца главы или до конца книги В таких случаях мы предусмотрели ссылки вперед, но вы должны быть способны без подготовки уловить суть каждого раздела.
9.1. Создание и управление процессами
В отличие от многих предшествующих и последующих операционных систем, создание процессов в Unix задумывалось (и было сделано) дешевым. Более того, Unix разделяет идеи «создания нового процесса» и «запуска данной программы в процессе». Это было элегантное проектное решение, которое упрощает многие операции.
9.1.1. Создание процесса: fork()
Первым шагом в запуске новой программы является вызов fork()
:
#include
#include
pid_t fork(void);
Использование fork()
просто. Перед вызовом один процесс, который мы называем fork()
возвращается, имеется уже два процесса: родительский и
Вот ключ: fork()
значении:
Если была ошибка, fork()
возвращает -1, а новый процесс не создается. Работу продолжает первоначальный процесс.
В порожденном процессе fork()
возвращает 0.
В родительском процессе fork()
возвращает положительный идентификационный номер (PID) порожденного процесса.
Код шаблона для создания порожденного процесса выглядит следующим образом:
pid_t child;
if ((child = fork()) < 0)
/* обработать ошибку */
else if (child == 0)
/* это новый процесс */
else
/* это первоначальный родительский процесс */
pid_t
является знаковым целым типом для хранения значений PID. Скорее всего, это просто int
, но специальный тип делает код более понятным, поэтому он должен использоваться вместо int
.