- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
При использовании setpgid() pgid должна быть группой существующего процесса, которая является частью текущего сеанса, фактически подключая pid к этой группе процессов. В противном случае pgid должна равняться pid, создавая новую группу процессов.
Имеется несколько значений для особых случаев как для pid, так и для pgid:
pid = 0 В данном случае setpgid() изменяет группу процессов вызывающего процесса на pgid. Это эквивалентно 'setpgid(getpid(), pgid)'.
pgid = 0 Это устанавливает ID группы процессов для данного процесса равным его PID. Таким образом, 'setpgid(pid, 0)' является тем же самым, что и 'setpgid(pid, pid)'. Это делает процесс с PID, равным pid, лидером группы процессов.
Во всех случаях лидеры сеанса являются особыми; их PID, ID группы процессов и ID сеанса идентичны, a ID группы процессов лидера не может быть изменена. (ID сеанса устанавливаются посредством setsid(), а получаются посредством getsid(). Это особые вызовы: см. справочные страницы setsid(2) и getsid(2)).
9.3. Базовое межпроцессное взаимодействие: каналы и очереди FIFO
Межпроцессное взаимодействие (Interprocess communication — IPC) соответствует своему названию: это способ взаимодействия для двух отдельных процессов. Самым старым способом IPC на системах Unix является канал (pipe): односторонняя линия связи. Данные, записанные в один конец канала, выходят из другого конца.
9.3.1. Каналы
Каналы проявляют себя как обычные дескрипторы файлов. Без особого разбирательства вы не можете сказать, представляет ли дескриптор файла сам файл или канал. Это особенность; программы, которые читают из стандартного ввода и записывают в стандартный вывод, не должны знать или заботиться о том, что они могут взаимодействовать с другим процессом. Если хотите знать, каноническим способом проверки этого является попытка выполнить с дескриптором 'lseek(fd, 0L, SEEK_CUR)'; этот вызов пытается отсчитать 0 байтов от текущего положения, т е. операция, которая ничего не делает[94]. Эта операция завершается неудачей для каналов и не наносит никакого вреда другим файлам.
9.3.1.1. Создание каналов
Системный вызов pipe() создает канал:
#include <unistd.h> /* POSIX */
int pipe(int filedes[2]);
Значение аргумента является адресом массива из двух элементов целого типа, pipe() возвращает 0 при успешном возвращении и -1, если была ошибка.
Если вызов был успешным, у процесса теперь есть два дополнительных открытых дескриптора файла. Значение filedes[0] является читаемым концом канала, a filedes [1] — записываемым концом. (Удобным мнемоническим способом запоминания является то, что читаемый конец использует индекс 0, аналогичный дескриптору стандартного ввода 0, а записываемый конец использует индекс 1, аналогичный дескриптору стандартного вывода 1.)
Как упоминалось, данные, записанные в записываемый конец, считываются из читаемого конца. После завершения работы с каналом оба конца закрываются с помощью вызова close(). Следующая простая программа, ch09-pipedemo.c, демонстрирует каналы путем создания канала, записи в него данных, а затем чтения этих данных из него:
1 /* ch09-pipedemo.c --- демонстрация ввода/вывода с каналом. */
2
3 #include <stdio.h>
4 #include <errno.h>
5 #include <unistd.h>
6
7 /* main --- создание канала, запись в него и чтение из него. */
8
9 int main(int argc, char **argv)
10 {
11 static const char mesg[] = "Don't Panic!"; /* известное сообщение */
12 char buf[BUFSIZ];
13 ssize_t rcount, wcount;
14 int pipefd[2];
15 size_t l;
16
17 if (pipe(pipefd) < 0) {
18 fprintf(stderr, "%s: pipe failed: %sn", argv[0],
19 strerror(errno));
20 exit(1);
21 }
22
23 printf("Read end = fd %d, write end = fd %dn",
24 pipefd[0], pipefd[1]);
25
26 l = strlen(mesg);
27 if ((wcount = write(pipefd[1], mesg, 1)) != 1) {
28 fprintf(stderr, "%s: write failed: %sn", argv[0],
29 strerror(errno));
30 exit(1);
31 }
32
33 if ((rcount = read(pipefd[0], buf, BUFSIZ)) != wcount) {
34 fprintf(stderr, "%s: read failed: %sn", argv[0],
35 strerror(errno));
36 exit(1);
37 }
38
39 buf[rcount] = ' ';
40
41 printf("Read <%s> from pipen", buf);
42 (void)close(pipefd[0]);
43 (void)close(pipefd[1]);
44
45 return 0;
46 }
Строки 11–15 объявляют локальные переменные; наибольший интерес представляет mesg, который представляет текст, проходящий по каналу.
Строки 17–21 создают канал с проверкой ошибок; строки 23–24 выводят значения новых дескрипторов файлов (просто для подтверждения, что они не равны 0, 1 или 2)
В строке 26 получают длину сообщения для использования с write(). Строки 27–31 записывают сообщение в канал, снова с проверкой ошибок.
Строки 33–37 считывают содержимое канала, опять с проверкой ошибок. Строка 39 предоставляет завершающий нулевой байт, так что прочитанные данные могут использоваться в качестве обычной строки. Строка 41 выводит данные, а строки 42–43 закрывают оба конца канала. Вот что происходит при запуске программы:
$ ch09-pipedemo
Read end = fd 3, write end = fd 4
Read <Don't Panic!> from pipe
Эта программа не делает ничего полезного, но она демонстрирует основы. Обратите внимание, что нет вызовов open() или creat() и что программа не использует три своих унаследованных дескриптора. Тем не менее, write() и read() завершаются успешно, показывая, что дескрипторы файлов действительны и что данные, поступающие в канал, действительно выходят из него.[95] Конечно, будь сообщение слишком большим, наша программа не работала бы. Это происходит из-за того, что размер (памяти) каналов ограничен, факт, который мы обсудим в следующем разделе.
Подобно другим дескрипторам файлов, дескрипторы для каналов наследуются порожденным процессом после fork, и если они не закрываются, все еще доступны после exec. Вскоре мы увидим, как использовать это обстоятельство и сделать с каналами что-то интересное.
9.3.1.2. Буферирование каналов
Каналы буферируют свои данные, что означает, что записанные в канал данные хранятся ядром до тех пор, пока не будут прочитаны. Однако, канал может содержать лишь такое-то количество записанных, но еще не прочитанных данных. Мы можем называть записывающий процесс производителем, а читающий процесс потребителем. Как система управляет полными и пустыми каналами?
Когда канал полон, система автоматически блокирует производителя в следующий раз, когда он пытается осуществить запись данных в канал с помощью write(). Когда канал освобождается, система копирует данные в канал, а затем позволяет системному вызову write() вернуться к производителю.
Подобным же образом, если канал пустой, потребитель блокируется в read() до тех пор, пока в канале не появятся данные для чтения. (Блокирующее поведение можно отключить; это обсуждается в разделе 9.4.3.4 «Неблокирующий ввод/вывод для каналов и очередей FIFO».)
Когда производитель вызывает на записывающем конце канала close(), потребитель может успешно прочесть любые данные, все еще находящиеся в канале. После этого дальнейшие вызовы read() возвращают 0, указывая на конец файла.
Напротив, если потребитель закрывает читаемый конец, write() на записываемом конце завершается неудачей. В частности, ядро посылает производителю сигнал «нарушенный канал», действием по умолчанию для которого является завершение процесса.
Нашей любимой аналогией для каналов является то, как муж и жена вместе моют и сушат тарелки. Один супруг моет тарелки, помещая чистые, но влажные тарелки в сушилку на раковине. Другой супруг вынимает тарелки из сушилки и вытирает их. Моющий тарелки является производителем, сушилка является каналом, а вытирающий является потребителем.[96]
Если вытирающий супруг оказывается быстрее моющего, сушилка становится пустой, и вытирающему приходится ждать, пока не будут готовы новые тарелки. Напротив, если быстрее вытирающий супруг, сушилка наполняется, и моющему приходится ждать, пока она не опустеет, прежде чем помещать в нее тарелки. Это изображено на рис. 9.3.
Рис. 9.3. Синхронизация процессов канала
9.3.2. Очереди FIFO

