Нужно ли очищать именованные каналы? - PullRequest
0 голосов
/ 03 мая 2018

Не могу найти, буферизуются ли именованные каналы, отсюда вопрос.

На странице написано https://linux.die.net/man/3/mkfifo:

Специальный файл FIFO похож на канал ... любой процесс может открыть его для чтения или записи, так же, как обычный файл.

Трубы не буферизируются, промывать не нужно. Но в обычном файле я бы fflush (или fsync) дескриптор файла.

Как насчет именованной трубы?

Ответы [ 2 ]

0 голосов
/ 05 мая 2018

Я не очень хорошо понимаю, что вы пытаетесь спросить, но, как вам уже сказали, каналы не больше, чем буфер.

Исторически сложилось, что fifos (или каналы) использовали прямые блоки inode, используемые для их обслуживания, и они привязаны к файлу (с именем или нет) в некоторой файловой системе.

Сегодня я не знаю точных деталей реализации для fifo, но в основном ядро ​​буферизует все данные, которые писатели уже написали, но читатели еще не прочитали. У fifo есть верхний предел (определенный системой) для объема буфера, который они могут поддерживать, но обычно он терпит неудачу около 10-20 КБ данных.

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

В любом случае, ваш вопрос о промывке не имеет ничего общего с трубами (ну, не так, позвольте мне объяснить), но с пакетом <stdio.h>. <stdio.h> делает буфер и обрабатывает буферизацию для каждого FILE * индивидуально, поэтому у вас есть вызовы для очистки буферов, когда вы хотите, чтобы они были write(2) n на диск.

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

Когда указатель FILE * связан с последовательным tty (он проверяет, что вызов на isatty(3) вызов, который внутренне делает вызов ioctl(2), позволяет <stdio.h> видеть, если вы против последовательного устройства , устройство char. Если это происходит, то <stdio.h> выполняет строковую буферизацию , что означает, что всегда, когда на устройство выводится символ '\n', буфер автоматически буферизуется.

Это предполагает проблему оптимизации, потому что, когда, например, вы используете cat(1) для копирования файла, самый большой буфер обычно предполагает наиболее эффективный подход. Ну, <stdio.h> приходит, чтобы решить проблему, потому что, когда вывод не является устройством tty, он выполняет полную буферизацию и очищает только внутренние буферы указателя FILE *, когда он полон данных.

Итак, вопрос: как <stdio.h> ведет себя с узлом fifo (или pipe)? Ответ прост .... is is not char device (или tty), поэтому <stdio.h> выполняет полную буферизацию на нем. Если вы обмениваетесь данными между двумя процессами и хотите, чтобы читатель получил данные, как только вы их printf(3) отредактировали, тогда вам лучше набрать fflush(3), потому что если вы этого не сделаете, вы можете ждать ответ, который никогда не приходит, потому что то, что вы написали, еще не было написано (не ядром, а библиотекой <stdio.h>)

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

0 голосов
/ 03 мая 2018

Трубы не буферизируются, промывка не требуется.

На самом деле я бы сказал иначе: для большинства намерений и целей каналы являются ничем иным, как буфером. Сбрасывать их не имеет смысла, потому что не существует базового устройства для приема данных.

Более того, хотя POSIX явно не запрещает дополнительную буферизацию конвейерного ввода / вывода, он предъявляет достаточные поведенческие требования, и я не думаю, что есть какой-либо способ определить из наблюдения, происходит ли такая буферизация, за исключением, возможно, fsync() преуспевает. Другими словами, даже если бы была дополнительная буферизация, необязательно fsync() конец трубы.

Но в обычном файле я fflush (или fsync) дескриптор файла.

Ну, нет, вы бы не 1017 * описатель файла. fflush() работает с потоками , представленными объектами FILE, а не с файловыми дескрипторами. Это принципиальное различие, потому что большинство потоков буферизуются на уровне библиотеки C, независимо от характера файла внизу. Именно с этим буфером библиотечного уровня взаимодействует fflush(). Вы можете управлять режимом буферизации потока на уровне библиотеки с помощью функции setvbuf().

В тех системах, которые его предоставляют, fsync() работает на другом, более низком уровне. Он дает указание ОС убедиться, что все данные, ранее записанные в указанный дескриптор файла, были доставлены на базовое устройство хранения. Другими словами, он очищает буферы уровня ОС.

Обратите внимание, что вы можете обернуть поток вокруг дескриптора файла конца канала с помощью функции fdopen(). Это не означает, что канал требует очистки больше, чем раньше, но поток будет буферизован по умолчанию, поэтому очистка будет иметь отношение к нему.

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

Как насчет именованной трубы?

Обсуждение выше о потоковом вводе / выводе против . Здесь также применяется ввод-вывод на основе дескриптора POSIX. Если вы обращаетесь к именованному каналу через поток, его взаимодействие с fflush() будет зависеть от буферизации этого потока.

Но я полагаю, ваш вопрос больше касается буферизации и очистки на уровне ОС. POSIX, кажется, не говорит о многом конкретном, но так как вы помечаете [linux] и ссылаетесь на страницу руководства Linux в своем вопросе, я предлагаю это в ответ:

Единственная разница между трубами и FIFO - это способ, которым они созданы и открыты. После того, как эти задачи были выполнены, Ввод / вывод на каналах и FIFO имеет точно такую ​​же семантику.

( Страница руководства Linux pipe (7). )

...