2009-10-28 3 views
24

두 개의 프로그램 인 Writer 및 Reader가 있습니다.다중 판독기가있는 유닉스에서 명명 된 파이프 (FIFO)

Writer에서 Reader로 FIFO가 있으므로 Writer에서 stdin에 뭔가 쓸 때 Reader에서 stdout으로 출력됩니다.

두 독자가 열려있는 상태에서이 작업을 시도했지만 두 Reader 프로그램 중 하나에서만 표준 출력에 출력되었습니다. 유닉스가 stdout을 인쇄하기로 선택한 독자 프로그램은 내가 실행할 때마다 임의적 인 것처럼 보였지만 일단 프로그램 중 하나를 선택하면 stdout에 대한 각 출력은 동일한 Reader 프로그램에서 출력된다.

왜 이런 일이 발생하는지 알고 있습니까?

두 개의 WRITER 프로그램이있는 경우 모두 동일한 파이프에 쓸 수 있습니다.

+0

데이터가 각 독자에게 "브로드 캐스트"되지 않는 이유 또는 데이터가 각 리더에 균등하게 분배되지 않는 이유를 알고 싶습니까? – Jacob

+0

Writer가 stdout (표준 입력 아님)에 쓰고 있다고 믿습니다. 이것은 FIFO입니다. 각 리더는 아마도 FIFO 인 자체 stdin에서 읽은 다음 자신의 표준 출력에 데이터를 쓰는 것으로 추정됩니다. –

+0

Jacob - 나는 왜 데이터가 두 독자 모두에게 전달되지 않는지 알고 싶다. –

답변

21

FIF O의 O는 "out"을 의미합니다. 데이터가 "출력"되면 사라집니다. :-) 당연히 다른 프로세스가 따라오고 다른 누군가가 이미 읽기를 발행 한 경우 데이터가 두 번있을 수 없습니다.

당신이 제안한 것을 성취하려면 유닉스 도메인 소켓을 조사해야합니다. 맨 페이지 here 파일 시스템 경로에 바인딩하여 클라이언트 프로세스에 쓸 수있는 서버를 작성할 수 있습니다. socket(), bind(), listen(), accept(), connect() 등 모두 PF_UNIX, AF_UNIXstruct sockaddr_un과 함께 사용하는 것이 좋습니다.

+0

아하! 그게 내가 생각한거야. 설명 주셔서 감사합니다! –

2

나는 당신이 관찰 한 행동이 우연의 일치라고 생각하지 않습니다. 두 독자와 작가로 루프로 '나오지도'사용합니다이 추적을 고려해 볼 수 있듯이

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 스크립트를 사용 했었지만 필자는 Reader 2의 모든 1 줄에 대해 Reader 1의 (일반적으로) 두 줄의 더 명확한 동작을 보았을 것입니다.

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

맥 OS X 10.5.8 (레오파드)에서 수행 실험 -하지만 가능성은 유사한 대부분의 장소가 될 수 있습니다.

+0

아, 그리고 그것이 가치있는 일이라면 두 독자 스크립트 모두에서 '수면 1'을 사용하여 Perl 변형을 시도했을 때 모든 것이 실행 중 하나에서 독자 2에 의해 처리되었습니다. 비대칭적인 자세로 시스템의 손을 강제로 잠자 요. –

+0

흥미로운 것은 ... 하나의 리더가 FIFO에서 읽은 후 데이터가 지워지고 다른 리더가 동일한 데이터를 읽을 수없는 것처럼 보입니다. –

+0

물론 데이터가 읽혀지면 소비되고 사라집니다. 그것이 요점입니다. 단말기와 동일 - 여러 프로세스가 데이터를 놓고 경쟁하는 경우 데이터를 얻고 서로 경쟁하지 않습니다. 혼란 스러울 때, 'somebigfile | 더'. –

10

Linux tee()가 사용자의 요구에 맞을 수도 있습니다. 이 기능은 리눅스 고유의 것입니다 :
여기 tee

참고를 참조하십시오.

+1

'tee'는 리눅스와 관련이 없습니다 http://www.opengroup.org/onlinepubs/9699919799/utilities/tee.html; 하지만 원래 질문의 유스 케이스에 도움이 될지 확신 할 수 없다. –

+2

C 함수 티를 가리키고있다. 명령이 아니고/궁극적으로 티를 말한다. 하지만이 기능이 다른 플랫폼/라이브러리에 구현되었는지 확실하지 않습니다. – Julian

+0

티가 훌륭합니다. 어려운 부분은 데이터 스트림을 30 회의 프리 프로세스 (preocess)로 처리 한 후에 데이터의 1/30을 처리 할 수 ​​있다는 것입니다. 어떻게 결과를 조합합니까? 하나의 독자와 많은 작성자가 필요합니다. 트릭은 30 개의 FIFO를 만들고, 리더에게 전체 출력을 읽는 "선택"을하도록하는 것입니다. HADOOP는 당신을 위해이 일을하기로되어 있지만, 그것은 비참하고 비 대한 프레임 워크입니다. 0mq와 같은 도구는 대부분의 언어에서 작동하는 가볍고 깨끗한 IPC를 수행합니다. –

1

필자는 위의 설명에 파이프 (맨 페이지에서 확인할 수는 없지만 예상되는 읽기)가 특정 크기 (Linux의 경우 4KB) 이하인 원자재라고 덧붙이고 싶습니다. 그래서 우리는 빈 파이프로 시작하고, 작가는 < = 4KiB 데이터를 파이프에 씁니다. 다음과 같이 생각합니다.

a) 작성자가 모든 데이터를 한 번에 작성합니다. 이것이 일어나고있는 동안 다른 프로세스는 파이프를 읽거나 파이프에 쓸 기회가 없습니다.

b) 리더 중 하나가 I/O를 수행하도록 예약되어 있습니다.

c) 선택한 판독기는 파이프에서 모든 데이터를 한 번에 읽고 나중에 일부 표준 출력으로 인쇄합니다.

독자 중 한 명에게서 출력물을 볼 때 이것이 설명 될 수 있다고 생각합니다. 작은 덩어리로 글쓰기를 시도하고, 글쓰기가 끝난 후 자고있게하십시오.

물론 다른 사람들은 각 데이터가 프로세스에서만 읽히는 이유에 대해 답변했습니다.

+0

* 작성자는 모든 데이터를 한 번에 작성합니다. 이것이 일어나고있는 동안 다른 프로세스는 파이프에서 읽거나 파이프에 쓰는 기회가 없습니다. * Linux에서는 틀림없이 false입니다. 작가는 파이프에서 판독기가 읽힐 때까지 차단합니다. 따라서 읽기와 쓰기는 항상 시간적으로 중복됩니다 (그러나 원 자성을 손상시키지 않습니다). – DepressedDaniel

관련 문제