LINUX.ORG.RU

Как правильно работать с FIFO?


0

1

Есть задача — несколько процессов пишут в FIFO, один читает. Порядок, в котором придут данные разных процессов не имеет значения, главное, чтобы эти данные не смешались (то есть например чтобы в середину строки, передаваемой одним процессом не попала часть строки от другого). Нужно ли предпринимать какие-то действия для этого (например, блокировать на время записи канал при помощи flock), или всё произойдёт само собой? Если важно — будут передаваться строки символов по 20, разделённые переводом строки.

★★★★

Само собой не произойдет. Нужно.

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

tekilla
()

Если есть уверенность, что порция данных пишется одним вызовом «write»,
то никаких дополнительных мер не нужно, атомарность записи для fifo гарантируется POSIX. Если нет (например пишущие процессы используют буферизованный вывод), то нужно.

ABW ★★★★★
()
Ответ на: комментарий от mashina

а где почитать про FIFO на UNIX? я как-то игнорировал этот инструмент, но теперь мне кажется что надо бы знать

поэтому хотелось бы из первоисточника прочитать про ограничения

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

в man 7 pipe что-то есть. Хотя, наверное, обманул, там пишут про минимум 512б

mashina ★★★★★
()
Ответ на: комментарий от mashina

А еще точнее, огранична PIPE_BUF.
На современных системах я меньше 4k не видел, но в ранних версиях POSIX упоминается >= 512b.

ABW ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Любое пособие по системным вызовам (UNIX API), в том числе man-ы.
Больше вроде негде.

ABW ★★★★★
()
Ответ на: Само собой не произойдет. Нужно. от tekilla

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

То есть блокировка через flock не подойдёт? Но это же как бы файл...

askh ★★★★
() автор топика
Ответ на: комментарий от askh

Почему не пойдет? flock ставится на собственно fd и от типа файла никоим образом не зависит. Только не забывай, что это
1) рекомендательная блокировка;
2) блокируется не доступ к файлу, а попытка получения блокировки на том же fd;
3) следовательно, о буферизованном выводе можно забыть.

ABW ★★★★★
()
Ответ на: комментарий от I-Love-Microsoft

Из примера видно, что скорость прокачки у TCP-сокета на localhost не хуже.
Но это, собственно, неинтересно. Интереснее затраты на создание и подключение, но это надо оценивать слишком хитрыми C-шными тестами.
Кроме того, на самом деле нюансов у сокетов ничуть не меньше, а код для работы с ними получается несколько длиннее.

ABW ★★★★★
()

Данные пишутся в буфер, по достижению размера буфера отправляются в файл. Можно менять размер буфера, можно сливать его принудительно.

Так любое i/o работает, fifo тут не исключение.

melkor217 ★★★★★
()
Ответ на: комментарий от askh

Unix-сокеты и именованные каналы предоставляют разную функциональность. С именованным каналом связан один буфер в ядре, вне зависимости от того, сколько процессов подключилось к этому каналу. Если писателей несколько, то порядок, в котором будут помещены их данные в буфер, не определён. Если данные, записываемые вызовом write() длиннее длины буфера, атомарность записи не обеспечивается, и могут перемешаться куски данных, записиваемые разными процессами. Если читателей несколько, то данные из буфера будут передаваться в процессы-читатели в случайной очерёдности. Поэтому канал обычно используют только для передачи данных в одном направлении к одному процессу-читателю. Для диалога один канал использовать невозможно. Зато работа с каналами ведётся теми же системными вызовани, что и работа с файлами: open(), read(), write(), close(). Поэтому каналами можно пользоваться в шелл скриптах. Кстати, lseek() и fcntl() advisory locking с каналами не работают.

Unix-сокеты предоставляют другую функциональность — индивидуальные соединения между процессом-клиентом и процессом-сервером. Сокеты могут быть поточными (без кадрирования) и дейтаграммными (с кадрированием). Работа с сокетами ведётся другими системными вызовами: socket(), bind(), listen(), accept(), connect(), recv(), send(). Процесс-клиент инициирует соединение с процессом сервером вызовом connect(). Процесс-сервер принимает соединение вызовом accept(). При этом вызов accept() каждый раз возвращает файловый дескриптор нового соединения. Каждое соединение имеет свою пару буферов. Можно узнать, кто на другом конце соединения (pid, euid, egid).

Поэтому

  • нужен диалог — используй сокет
  • нужны сообщения длиннее 4K — используй сокет
  • нужно идентифицировать отправителя — используй сокет
  • иначе используй именованный канал
iliyap ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.