- •Введение
- •Глава 1. Фундаментальные концепции unix Систем
- •Программы, процессы и потоки
- •Сигналы
- •Идентификаторы процессов, группы процессов и сеансы
- •Система прав
- •Другие атрибуты процесса
- •Межпроцессное взаимодействие
- •Использование системных вызовов
- •Краткие описания функций и обработка ошибок
- •Контрольные вопросы
- •Литература
- •Глава 2. Базовые операции ввода-вывода
- •Файловые операции ввода - вывода
- •Стандартные дескрипторы
- •Системные вызовы open и creat
- •Системный вызов umask
- •Системный вызов unlink
- •Текущая позиция в файле
- •Системный вызов write
- •2.8. Системный вызов read
- •2.9. Системный вызов close
- •2.10. Системный вызов lseek
- •2.11. Системные вызовы pread и pwrite
- •2.12. Системные вызовы truncate и ftruncate
- •Контрольные вопросы
- •Литература
- •Глава 3. Дополнительные операции файлового ввода_вывода
- •Низкоуровневый доступ к файловой системе
- •Жесткие и символические ссылки
- •Системный вызов getcwd
- •Отображение метаданных файла
- •Системные вызовы getpwuid, getgrgid и getlogin
- •Каталоги
- •Системные вызовы chdir и fchdir
- •Системные вызовы mkdir и rmdir
- •Контрольные вопросы
- •Литература
- •Глава 4. Процессы и потоки
- •4.1. Среда окружения
- •Системный вызов exec
- •Системный вызов fork
- •Завершение процесса и системные вызовы exit
- •Системные вызовы wait, waitpid и waitid
- •Получение и изменение идентификаторов пользователя и группы
- •Получение и изменение приоритета
- •Контрольные вопросы
- •Литература
- •Глава 5. Механизмы межпроцессного взаимодействия
- •5.1. Каналы
- •5.2. Системные вызовы dup и dup2
- •5.3. Двунаправленное взаимодействие с использованием однонаправленных каналов
- •Контрольные вопросы
- •Литература
- •Глава 6.Механизмы взаимодействия процессов
- •Именованные каналы (fifo)
- •Системные вызовы для работы с очередями сообщений posix
- •Семафоры
- •Системные вызовы для работы с общей памятью posix
- •Контрольные вопросы
- •Литература
- •Глава 7.Сетевое взаимодействие и сокеты
- •Основные системные вызовы для работы с сокетами, образующими логические соединения
- •Обслуживание нескольких клиентов
- •Адресация сокетов
- •In_port_t sin_port; /* номер порта (uint16_t) */
- •In_addr_t s_addr; /* адрес iPv4 (uint32_t) */
- •Домен адресов af_inet6
- •In_port_t sin6_port; /* номер порта (uint16_t) */
- •Доменная система именования
- •Параметры сокетов
- •Контрольные вопросы
- •Литература
- •Глава 8.Сигналы и таймеры
- •Введение в сигналы
- •Жизненный цикл сигналов
- •Типы сигналов
- •Системный вызов sigaction
- •Контрольные вопросы
- •Литература
- •Заключение
- •Список литературы
- •Глава 2. Базовые операции ввода-вывода 14
- •Глава 3. Дополнительные операции файлового ввода_вывода 25
- •Глава 6. Механизмы взаимодействия процессов 58
Системный вызов fork
Данный вызов запускает новый процесс, но не новую программу, где новый процесс – это точная копия старого со всеми его данными:
fork - создает новый процесс
#include <unistd.h>
pid_t fork(void);
/* Возвращает идентификатор дочернего процесса или 0 в случае успеха и -1 в случае ошибки (код ошибки - в переменной errno) */
По завершении fork оба процесса получают от него возвращаемое значение. В зависимости от него реакция потомка и предка может сильно отличаться. Обычно процесс-потомок сразу же вызывает exec для запуска новой программы, а предок может либо подождать завершения процесса-потомка, либо заняться своими делами.
Процесс-потомок получает от вызова fork значение 0, родительский процесс - идентификатор процесса-потомка. Возвращаемое значение -1 свидетельствует об ошибке, но поскольку fork не имеет входных аргументов, то ошибочная ситуация никак не связана с вызывающим процессом. Единственная возможная ошибка – исчерпание системных ресурсов, то есть либо нехватка места в файле подкачки, либо в системе исполняется слишком много процессов.
При создании нового процесса вызовом fork процесс-потомок наследует атрибуты от родителя как результат копирования сегмента системных данных предка. Такого рода наследование позволяет пользователю установить атрибуты в командной оболочке, например, текущий каталог, действующий идентификатор пользователя и приоритет, которые затем будут автоматически передаваться всем запускаемым командам. Для наследования недоступно лишь несколько атрибутов:
идентификаторы процессов у потомка и предка будут отличаться;
если в рамках родительского процесса было запущено несколько потоков, то потомок унаследует только один, тот который вызвал fork;
потомок получает от родителя дубликаты открытых дескрипторов. Они соответствуют одним и тем же файлам. Они совместно используют одни и те же записи в системной таблице файлов, а значит и текущие позиции в файлах у них будут одни и те же. Если потомок изменит ее с помощью lseek, то следующая операция ввода-вывода предка будет производиться с новой текущей позиции. Однако сами файловые дескрипторы у предка и потомка разные. Если потомок закроет свой дескриптор, то соответствующий дескриптор предка по-прежнему останется открытым;
процесс-потомок сбрасывает накапливаемые значения времени исполнения в пространстве пользователя и ядра в ноль, потому что был порожден новый процесс.
Рассмотрим пример, демонстрирующий работу системного вызова fork:
void forktest(void)
{
int pid;
printf(“Начало теста \n”, pid);
pid = fork();
printf(“Возвращаемое значение %d\n”, pid);
}
Результат работы:
$ forktest
Начало теста
Возвращаемое значение 76542
Возвращаемое значение 0
$
В данной ситуации предок первым вывел свое сообщение, но это совершенно необязательно. Если очередность исполнения имеет значение, процессы можно синхронизировать. Сделать это можно с помощью каналов или сигналов. Перезапустим пример forktest, перенаправив вывод в файл:
$ forktest > tmp
$ cat tmp
Начало теста
Возвращаемое значение 65875
Начало теста
Возвращаемое значение 0
$
Сообщение «Начало теста» получено дважды. Это произошло из-за буферизации вывода - потомок, вместе со всем остальным, унаследовал от предка и частично заполненный выходной буфер. Когда потомок завершил свою работу, его буфер был, вытолкнут, то же самое произошло и с предком. В предыдущем испытании printf не буферизовала свой вывод, поскольку знала, что устройством стандартного вывода является терминал, который предполагает более интерактивный режим работы.