Подтвердить что ты не робот

Именованные каналы (FIFO) в Unix с несколькими считывателями

У меня есть две программы: Writer и Reader.

У меня есть FIFO от Writer to Reader, поэтому, когда я пишу что-то в stdin в Writer, он печатается в stdout из Reader.

Я попытался сделать это с открытием TWO Readers, и я получил вывод на stdout только из одной из двух программ Reader. Какая программа Reader Unix выбирает для печати stdout, казалось, была произвольной при каждом ее запуске, но как только она выбирает одну из программ, каждый вывод на stdout печатается из одной программы Reader.

Кто-нибудь знает, почему это происходит?

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

4b9b3361

Ответ 1

O в FIF O означает "выход". Как только ваши данные "вне", они исчезли.:-) Так естественно, если другой процесс идет, и кто-то еще уже выпустил чтение, данные не будут там дважды.

Чтобы выполнить то, что вы предлагаете, вы должны посмотреть в сокеты домена Unix. Manpage здесь. Вы можете написать сервер, который может писать в клиентские процессы, привязывая к пути файловой системы. См. Также socket(), bind(), listen(), accept(), connect(), все из которых вы хотите использовать с PF_UNIX, AF_UNIX и struct sockaddr_un.

Ответ 2

Linux tee() может удовлетворить ваши потребности.
см. здесь tee

ПРИМЕЧАНИЕ. эта функция специфична для Linux.

Ответ 3

Я не думаю, что поведение, которое вы наблюдаете, более чем случайно. Рассмотрим этот след, который использует "sed" как два считывателя и петлю как писатель:

Osiris JL: mkdir fifo
Osiris JL: cd fifo
Osiris JL: mkfifo fifo
Osiris JL: sed 's/^/1: /' < fifo &
[1] 4235
Osiris JL: sed 's/^/2: /' < fifo &
[2] 4237
Osiris JL: while read line ; do echo $line; done > fifo < /etc/passwd
1: ##
1: # User Database
1: #
1: # Note that this file is consulted directly only when the system is running
1: # in single-user mode. At other times this information is provided by
1: # Open Directory.
1: #
1: # This file will not be consulted for authentication unless the BSD local node
1: # is enabled via /Applications/Utilities/Directory Utility.app
1: #
1: # See the DirectoryService(8) man page for additional information about
1: # Open Directory.
1: ##
1: nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
1: root:*:0:0:System Administrator:/var/root:/bin/sh
1: daemon:*:1:1:System Services:/var/root:/usr/bin/false
1: _uucp:*:4:4:Unix to Unix Copy Protocol:/var/spool/uucp:/usr/sbin/uucico
1: _lp:*:26:26:Printing Services:/var/spool/cups:/usr/bin/false
2: _postfix:*:27:27:Postfix Mail Server:/var/spool/postfix:/usr/bin/false
2: _mcxalr:*:54:54:MCX AppLaunch:/var/empty:/usr/bin/false
2: _pcastagent:*:55:55:Podcast Producer Agent:/var/pcast/agent:/usr/bin/false
2: _pcastserver:*:56:56:Podcast Producer Server:/var/pcast/server:/usr/bin/false
2: _serialnumberd:*:58:58:Serial Number Daemon:/var/empty:/usr/bin/false
2: _devdocs:*:59:59:Developer Documentation:/var/empty:/usr/bin/false
2: _sandbox:*:60:60:Seatbelt:/var/empty:/usr/bin/false
2: _mdnsresponder:*:65:65:mDNSResponder:/var/empty:/usr/bin/false
2: _ard:*:67:67:Apple Remote Desktop:/var/empty:/usr/bin/false
2: _www:*:70:70:World Wide Web Server:/Library/WebServer:/usr/bin/false
2: _eppc:*:71:71:Apple Events User:/var/empty:/usr/bin/false
2: _cvs:*:72:72:CVS Server:/var/empty:/usr/bin/false
2: _svn:*:73:73:SVN Server:/var/empty:/usr/bin/false
2: _mysql:*:74:74:MySQL Server:/var/empty:/usr/bin/false
2: _sshd:*:75:75:sshd Privilege separation:/var/empty:/usr/bin/false
2: _qtss:*:76:76:QuickTime Streaming Server:/var/empty:/usr/bin/false
2: _cyrus:*:77:6:Cyrus Administrator:/var/imap:/usr/bin/false
2: _mailman:*:78:78:Mailman List Server:/var/empty:/usr/bin/false
2: _appserver:*:79:79:Application Server:/var/empty:/usr/bin/false
2: _clamav:*:82:82:ClamAV Daemon:/var/virusmails:/usr/bin/false
2: _amavisd:*:83:83:AMaViS Daemon:/var/virusmails:/usr/bin/false
2: _jabber:*:84:84:Jabber XMPP Server:/var/empty:/usr/bin/false
2: _xgridcontroller:*:85:85:Xgrid Controller:/var/xgrid/controller:/usr/bin/false
2: _xgridagent:*:86:86:Xgrid Agent:/var/xgrid/agent:/usr/bin/false
2: _appowner:*:87:87:Application Owner:/var/empty:/usr/bin/false
2: _windowserver:*:88:88:WindowServer:/var/empty:/usr/bin/false
2: _spotlight:*:89:89:Spotlight:/var/empty:/usr/bin/false
2: _tokend:*:91:91:Token Daemon:/var/empty:/usr/bin/false
2: _securityagent:*:92:92:SecurityAgent:/var/empty:/usr/bin/false
2: _calendar:*:93:93:Calendar:/var/empty:/usr/bin/false
2: _teamsserver:*:94:94:TeamsServer:/var/teamsserver:/usr/bin/false
2: _update_sharing:*:95:-2:Update Sharing:/var/empty:/usr/bin/false
2: _installer:*:96:-2:Installer:/var/empty:/usr/bin/false
2: _atsserver:*:97:97:ATS Server:/var/empty:/usr/bin/false
2: _unknown:*:99:99:Unknown User:/var/empty:/usr/bin/false
Osiris JL:  jobs
[1]-  Running                 sed 's/^/1: /' < fifo &
[2]+  Done                    sed 's/^/2: /' < fifo
Osiris JL: echo > fifo
1: 
Osiris JL: jobs
[1]+  Done                    sed 's/^/1: /' < fifo
Osiris JL: 

Как вы можете видеть, оба читателя прочитали некоторые данные. Какой из читателей был запланирован в любое время, зависел от прихоти o/s. Обратите внимание, что я тщательно использовал эхо для печати каждой строки файла; это были атомные записи, которые читались атомарно.

Если бы я использовал Perl script, например, после прочтения и повторения строки, я мог бы увидеть более определенное поведение с (обычно) двумя строками из Reader 1 для каждой 1 строки из Reader 2.

perl -n -e 'while(<>){ print "1: $_"; sleep 1; }' < fifo &
perl -n -e 'while(<>){ print "2: $_"; sleep 2; }' < fifo &

Эксперимент, выполненный на MacOS X 10.5.8 (Leopard), но скорее всего будет похож на большинство мест.

Ответ 4

Я хотел бы добавить к приведенным выше объяснениям, что записи (и предположительные чтения, хотя я не могу подтвердить это из manpages), чтобы трубы были атомарными до определенного размера (4KiB в Linux). Итак, предположим, что мы начинаем с пустой трубы, и писатель записывает данные <= 4KiB в трубу. Вот что я думаю:

a) Писатель записывает все данные за один раз. В то время как это происходит, никакой другой процесс не имеет возможности читать (или писать) трубу.

b) Один из читателей планирует сделать это I/O.

c) Выбранный читатель считывает все данные из трубы за один раз и в какое-то время отпечатывает их на своем выводе.

Я думаю, это может объяснить, когда вы видите вывод только от одного из читателей. Попробуйте писать в небольших кусках и, возможно, спать после каждой записи.

Конечно, другие ответили, почему каждая точка отсчета считывается только процессом.

Ответ 5

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