- •Введение
- •Глава 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
5.3. Двунаправленное взаимодействие с использованием однонаправленных каналов
Типичная командная оболочка не позволяет организовать двунаправленное взаимодействие процессов. Двунаправленные конвейеры создаются в программах, написанных на языке С. Начнем с простого примера. Допустим, мы хотим вызвать в программе команду sort для сортировки данных. Конечно, это можно было бы сделать подобным образом:
system(“sort < файл_с_данными > файл_вывода”);
После этого можно прочитать отсортированные данные из файла_вывода. Нам нужно, чтобы команда sort получила данные по каналу и отправила нам отсортированный вывод тоже по каналу. Команда sort может читать свой стандартный источник ввода и записывать данные в стандартный вывод. Нам уже известно, как сделать произвольный дескриптор файла стандартным вводом или выводом процесса. В следующем примере воспользуемся двумя каналами, каждый из которых будет обрабатывать однонаправленный трафик. Один канал будет обрабатывать данные, поступающие к sort, а второй – данные, передаваемые обратно:
void fsort(void)
{
int pfdout[2], pfdin[2], fd;
ssize_t nread;
pid_t pid;
char buf[512];
pipe(pfdout);
pipe(pfdin);
pid = fork();
if (pid ==0) { /* дочерний процесс */
dup2(pfdout[0], STDIN_FILENO);
close(pfdout[0]);
close(pfdout[1]);
dup2(pfdin[1], STDOUT_FILENO);
close(pfdin[0]);
close(pfdin[1]);
execlp(“sort”, “sort”, NULL);
EC_FAIL
}
/* родительский процесс */
close(pfdout[0]);
close(pfdin[1]);
fd = open(“datafile”, O_RDONLY);
while (true) {
nread = read(fd, buf, sizeof(buf));
if (nread == 0)
break;
write(pfdout[1], buf, nread);
}
close(fd);
close(pfdout[1]);
while (true) {
nread = read(pfdin[0], buf, sizeof(buf));
if (nread == 0)
break;
write(STDOUT_FILENO, buf, nread);
}
close(pfdin[0]);
waitpid(pid, NULL, 0);
return;
EC_CLEANUP_BGN
EC_FLUSH(“fsort”);
EC_CLEANUP_END
}
Содержимое файла datafile таково:
mango
tomato
banana
apple
В результате выполнения программы получим следующее:
apple
banana
mango
tomato
При использовании двух каналов взаимоблокировка все же возможна, хотя и в не нашем примере. Она произошла, если бы родительский процесс, записывая данные в свой канал вывода, заблокировался по причине его заполнения, а дочерний процесс вместо очистки канала записал родительскому процессу много данных и заблокировался на втором канале. Чтобы исключить взаимоблокировку, каждую ситуацию нужно тщательно исследовать, и не только при небольших объемах текстовых данных.
Контрольные вопросы
Можно ли реализовать оператор go to как внешнюю команду, чтобы она выполнялась как дочерний процесс?
Напишите программу, которая записывает свой идентификатор процесса в стандартный вывод, после чего читает список идентификаторов процессов из своего стандартного источника ввода. Если в списке есть ее собственный идентификатор, она выводит список, в противном случае добавляет в список свой идентификатор процесса и записывает весь список в свой стандартный вывод. Затем все повторяется. Создайте пять процессов, выполняющих эту программу, организуйте их в кольцо и позвольте им немного поиграть.
Напишите клиентскую программу для калькулятора, позволяющую пользователю вводить выражение с использованием инфиксной нотации (2+3).
Напишите клиентскую программу для калькулятора, позволяющую пользователю вводить выражение с использованием постфиксной нотации (2 3+).
Измените, последний пример из раздела 5.2 так, чтобы процесс wc был родителем who.