Named Pipes (FIFOs) su Unix con più lettori

Ho due programmi, Writer e Reader.

Ho un FIFO da Writer a Reader, quindi quando scrivo qualcosa su stdin in Writer, viene stampato su stdout da Reader.

Ho provato a farlo con DUE Lettori aperti e ho ottenuto l’output su stdout da uno solo dei due programmi Reader. Quale programma Reader scelto da Unix per stampare lo stdout sembra essere arbitrario ogni volta che lo eseguo, ma una volta scelto uno dei programmi, ogni output su stdout viene stampato dallo stesso programma Reader.

Qualcuno sa perché questo accade?

Se ho due programmi WRITER, entrambi scrivono sullo stesso tubo okay.

L’O in FIF O significa “fuori”. Una volta che i tuoi dati sono “fuori”, non ci sono più. 🙂 Quindi, naturalmente, se un altro processo arriva e qualcun altro ha già emesso una lettura, i dati non saranno lì due volte.

Per realizzare ciò che suggerisci, dovresti esaminare i socket di dominio Unix. Manpage qui . È ansible scrivere un server in grado di scrivere sui processi client, associandolo a un percorso del file system. Vedi anche socket() , bind() , listen() , accept() , connect() , che tutti vorrai usare con PF_UNIX , AF_UNIX e struct sockaddr_un .

Linux tee () può soddisfare le tue esigenze.
vedi qui tee

NOTA: questa funzione è specifica per Linux.

Non penso che il comportamento che hai osservato sia più che casuale. Considera questa traccia, che usa “sed” come i due lettori e un ciclo come lo scrittore:

 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: 

Come puoi vedere, entrambi i lettori hanno letto alcuni dati. Quale lettore era in programma in qualsiasi momento dipendeva dal capriccio dell'o / s. Si noti che ho usato con attenzione un eco per stampare ogni riga del file; quelle erano scritture atomiche che venivano lette atomicamente.

Se avessi usato uno script Perl con, per esempio, un ritardo dopo aver letto ed echeggiato una riga, avrei potuto vedere un comportamento più determinato con (generalmente) due righe da Reader 1 per ogni 1 riga di Reader 2.

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

Sperimentazione fatta su MacOS X 10.5.8 (Leopard) - ma probabilmente simile nella maggior parte dei posti.

Vorrei aggiungere alle spiegazioni di cui sopra che le scritture (e le presunte letture, anche se non ho potuto confermarlo dalle manpage) alle pipe sono atomiche fino a una certa dimensione (4KiB su Linux). Quindi supponiamo di iniziare con una pipe vuota, e lo scrittore scrive <= 4KiB data to the pipe. Ecco cosa penso che succede:

a) Lo scrittore scrive tutti i dati in un colpo solo. Mentre questo sta accadendo, nessun altro processo ha la possibilità di leggere (o scrivere) sulla pipe.

b) È previsto che uno dei lettori esegua l’I / O.

c) Il lettore scelto legge tutti i dati dal tubo in un colpo solo e in un secondo momento li stampa sul suo stdout.

Penso che questo potrebbe spiegare mentre vedi l’output di uno solo dei lettori. Prova a scrivere in blocchi più piccoli, e magari dormi dopo ogni scrittura.

Ovviamente, altri hanno risposto perché ogni dato viene letto solo da processo.