Вход/Регистрация
Linux программирование в примерах
вернуться

Роббинс Арнольд

Шрифт:

Строки 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] Конечно, будь сообщение слишком большим, наша программа не работала бы. Это происходит из-за того, что размер (памяти) каналов ограничен, факт, который мы обсудим в следующем разделе.

95

Мы уверены, что вы не волновались. В конце концов, вы, возможно, используете конвейеры из оболочки десятки раз в день — Примеч. автора.

Подобно другим дескрипторам файлов, дескрипторы для каналов наследуются порожденным процессом после

fork
, и если они не закрываются, все еще доступны после
exec
. Вскоре мы увидим, как использовать это обстоятельство и сделать с каналами что-то интересное.

9.3.1.2. Буферирование каналов

Каналы буферируют свои данные, что означает, что записанные в канал данные хранятся ядром до тех пор, пока не будут прочитаны. Однако, канал может содержать лишь такое-то количество записанных, но еще не прочитанных данных. Мы можем называть записывающий процесс производителем, а читающий процесс потребителем. Как система управляет полными и пустыми каналами?

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

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

Подобным же образом, если канал пустой, потребитель блокируется в

read
до тех пор, пока в канале не появятся данные для чтения. (Блокирующее поведение можно отключить; это обсуждается в разделе 9.4.3.4 «Неблокирующий ввод/вывод для каналов и очередей FIFO».)

Когда производитель вызывает на записывающем конце канала

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

Напротив, если потребитель закрывает читаемый конец,

write
на записываемом конце завершается неудачей. В частности, ядро посылает производителю сигнал «нарушенный канал», действием по умолчанию для которого является завершение процесса.

Нашей любимой аналогией для каналов является то, как муж и жена вместе моют и сушат тарелки. Один супруг моет тарелки, помещая чистые, но влажные тарелки в сушилку на раковине. Другой супруг вынимает тарелки из сушилки и вытирает их. Моющий тарелки является производителем, сушилка является каналом, а вытирающий является потребителем. [96]

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

96

Что они ели на обед, остается не указанным. — Примеч. автора.

Рис. 9.3. Синхронизация процессов канала

9.3.2. Очереди FIFO

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

Это может быть серьезным ограничением. Многие системные службы запускаются как демоны, отсоединенные долгоживущие процессы. Должен быть способ отправки данных таким процессам (и, возможно, получения данных от них). Файлы для этого не подходят; синхронизация трудна или невозможна, а каналы для выполнения задания не могут быть созданы, поскольку нет общих предков.

Для решения этой проблемы System III предложила идею о FIFO. FIFO, [97] или именованный канал, является файлом в файловой системе, который действует подобно каналу. Другими словами, один процесс открывает FIFO для записи, тогда как другой открывает его для чтения. Затем данные, записанные; в FIFO, читаются читателем. Данные буферируются ядром, а не хранятся на диске.

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

97

FIFO означает «first in, first out» — «первым вошел, первым вышел». Так работают каналы. — Примеч. автора.

  • Читать дальше
  • 1
  • ...
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: