web-dev-qa-db-ja.com

複数のリーダーを持つUnix上の名前付きパイプ(FIFO)

WriterとReaderの2つのプログラムがあります。

私はFIFO WriterからReaderに持っているので、Writerでstdinに何かを書き込むと、Readerからstdoutに出力されます。

2つのReadersを開いた状態でこれを試してみたところ、2つのReaderプログラムのうちの1つだけからstdoutに出力されました。 Unixがstdoutの印刷を選択するリーダープログラムは、これを実行するたびに任意のように見えますが、プログラムの1つを選択すると、stdoutへの各出力は同じリーダープログラムから印刷されます。

なぜこれが起こるのか誰か知っていますか?

2つのWRITERプログラムがある場合、どちらも同じパイプに書き込みます。

35
Vlad the Impala

FIFのOO 「アウト」を意味します。データが「アウト」されると、データは失われます。 :-)したがって、当然、別のプロセスが発生し、他の誰かがすでに読み取りを発行している場合、データは2回存在しません。

提案することを達成するには、Unixドメインソケットを調べる必要があります。マンページ ここ 。ファイルシステムパスにバインドして、クライアントプロセスに書き込むことができるサーバーを作成できます。関連項目 socket()bind()listen()accept()connect() 、これらすべてをPF_UNIXAF_UNIX、およびstruct sockaddr_un

28
asveikau

Linux tee()はあなたのニーズに合うかもしれません。
ここを参照 ティー

注:この関数はLinux固有です。

11
Julian

あなたが観察した行動は偶然以上のものではないと思います。 2つのリーダーとして「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スクリプトを使用した場合、リーダー2からの1行ごとに(通常)リーダー1からの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)で実験が行われましたが、ほとんどの場所で類似している可能性があります。

2

上記の説明に加えて、パイプへの書き込み(およびマンページでは確認できませんでしたが、想定される読み取り)は特定のサイズ(Linuxでは4KiB)までアトミックであることを説明します。それでは、空のパイプから始めて、ライターがパイプに<= 4KiBのデータを書き込むとします。これが私が起こると思うことです:

a)ライターはすべてのデータを一度に書き込みます。これが発生している間、他のプロセスはパイプから読み取る(または書き込む)機会がありません。

b)リーダーの1人がI/Oを実行するようにスケジュールされています。

c)選択されたリーダーは、パイプからすべてのデータを一度に読み取り、後でそれらを標準出力に出力します。

これは、読者の1人だけからの出力を見ているときに説明できると思います。小さなチャンクで書き込みを試み、おそらく各書き込みの後にスリープします。

もちろん、なぜ他の人たちは、各データがプロセスのみによって読み取られるのかと答えました。

ソケットソリューションは機能しますが、サーバーがクラッシュすると複雑になります。任意のプロセスをサーバーにできるようにするため、特定のファイルの場所/長さ/データの変更を含む一時ファイルの最後にレコードロックを使用します。一時的な名前付きパイプを使用して、一時ファイルの最後に書き込みロックがあるプロセスに追加要求を通知します。

0
Paul Coelho