Domanda

Sono interessato a scrivere moduli di programma separati che funzionano fili indipendenti da poter agganciare insieme con i tubi. La motivazione sarebbe che ho potuto scrivere e testare ogni modulo completamente indipendente, forse persino scrivere in lingue diverse, o eseguire i diversi moduli su macchine diverse. Ci sono una vasta gamma di possibilità. Ho usato tubazioni per un po ', ma io sono familiarità con le sfumature del suo comportamento.

  • Sembra che alla fine di ricezione bloccherà in attesa di input, che mi sarei aspettato, ma la testata di invio a volte in attesa che qualcuno a leggere dal flusso?
  • Se scrivo un EOF al flusso posso continuare a continuare a scrivere a quel flusso fino a quando io lo chiudo?
  • Ci sono differenze nel comportamento di nome e tubi senza nome?
  • Ha importanza quale estremità del tubo apro prima con named pipe?
  • è il comportamento dei tubi coerenti tra i diversi sistemi Linux?
  • Fa il comportamento dei tubi dipende dalla shell che sto utilizzando o il modo in cui ho configurato esso?
  • Ci sono altre domande che dovremmo porci o problemi dovrei essere a conoscenza di se voglio usare tubi in questo modo?
È stato utile?

Soluzione

Wow, che è un sacco di domande. Vediamo se riesco a coprire tutto ...

  

Sembra che alla fine ricevente   blocco in attesa di input, che sarebbe   aspettare

Si vede correttamente un 'leggere' chiamata effettiva bloccherà fino a quando qualcosa c'è. Tuttavia, credo che ci sono alcune funzioni C che vi permetteranno di 'peek' a che cosa (e quanto) è in attesa nel tubo. Purtroppo, non mi ricordo se questo blocca pure.

  

sarà la testata di invio volte   in attesa che qualcuno a leggere dalla   flusso

No, l'invio non dovrebbe mai bloccare. Pensate alle conseguenze se questo fosse un tubo attraverso la rete a un altro computer. Vorresti aspettare (attraverso possibilmente ad alta latenza) per l'altro computer per rispondere che ha ricevuto esso? Ora, questo è un caso diverso se il manico del lettore della destinazione è stato chiuso. In questo caso, si dovrebbe avere qualche errore di controllo per gestire questo.

  

Se scrivo un EOF al flusso posso   mantenere continuare a scrivere a quel flusso   fino a quando la chiudo

Vorrei pensare questo dipende da quale lingua si sta utilizzando e la sua attuazione di tubi. In C, direi di no. In una shell di Linux, direi di sì. Qualcun altro con più esperienza avrebbe dovuto rispondere.

  

Ci sono differenze nel comportamento   di nome e di pipe senza nome?   Per quanto ne so, sì. Tuttavia, non ho molta esperienza con nome vs senza nome. Credo che la differenza è:

  • direzione Single vs comunicazione bidirezionale
  • di lettura e scrittura per il "in" e "out" i flussi di un filo
  

È importante l'estremità del tubo I   aprire prima con named pipe?

In genere no, ma si potrebbe incorrere in problemi di inizializzazione cercando di creare e collegare i fili con l'altro. Avresti bisogno di avere un thread principale che crea tutti i sub-thread e sincronizza i loro rispettivi tubi tra loro.

  

è il comportamento dei tubi coerenti   tra i diversi sistemi linux?

Ancora una volta, questo dipende da ciò che il linguaggio, ma in generale sì. Mai sentito parlare di POSIX? Questo è lo standard (almeno per Linux, Windows lo fa proprio cosa).

  

Fa il comportamento dei tubi dipende   sul guscio che sto utilizzando o il modo in cui ho   configurato?

Questa è sempre in un po 'di più di una zona grigia. La risposta dovrebbe esservi poiché il serbatoio dovrebbe essere essenzialmente le chiamate di sistema. Tuttavia, tutto fino a quel momento è in palio.

  

Ci sono altre domande che dovrebbero   essere chiedendo

Le domande che hai chiesto dimostra che avete una conoscenza discreta del sistema. Mantenere la ricerca e concentrarsi su quale livello si sta andando a lavorare su (shell, C, ecc). Imparerete molto di più da solo cercando però.

Altri suggerimenti

Questo è tutto basato su un sistema UNIX-like; Non ho familiarità con il comportamento specifico delle recenti versioni di Windows.

Sembra che alla fine di ricezione bloccherà in attesa di input, che mi sarei aspettato, ma sarà la testata di invio a volte in attesa che qualcuno a leggere dal flusso?

Sì, anche se su una macchina moderna che non può accadere spesso. Il tubo ha un buffer intermedio che possono potenzialmente riempire. Se lo fa, il lato di scrittura del tubo sarà effettivamente bloccare. Ma se ci pensate, non ci sono un sacco di file che sono abbastanza grande per rischiare di questo.

Se scrivo un EOF al flusso posso continuare a continuare a scrivere a quel flusso fino a quando io lo chiudo?

Um, si intende come un CTRL-D, 0x04? Certo, fino a quando il flusso è impostato in questo modo. Viz.

506 # cat | od -c
abc
^D
efg
0000000    a   b   c  \n 004  \n   e   f   g  \n                        
0000012

Ci sono differenze nel comportamento di nome e tubi senza nome?

Sì, ma sono sottili e l'attuazione dipendente. Il più grande è che si può scrivere a una named pipe prima che l'altra estremità è in esecuzione; con tubi senza nome, i descrittori di file vengono condivisi durante il processo fork / exec, quindi non c'è modo per accedere al buffer provvisorio senza processi fino.

Ha importanza quale estremità del tubo apro prima con named pipe?

No.

è il comportamento dei tubi coerenti tra i diversi sistemi linux?

Entro limiti ragionevoli, sì. Buffer dimensioni ecc possono variare.

fa il comportamento dei tubi dipende dalla shell che sto utilizzando o il modo in cui ho configurato esso?

No. Quando si crea un tubo, sotto le coperte quello che succede è il vostro processo genitore (il guscio) crea un tubo che ha una coppia di descrittori di file, poi fa un exec forchetta come questo pseudocodice:

principale :

create pipe, returning two file descriptors, call them fd[0] and fd[1]
fork write-side process
fork read-side process

Scrivi lato :

close fd[0]
connect fd[1] to stdout
exec writer program

Leggi lato :

close fd[1]
connect fd[0] to stdin
exec reader program

Ci sono altre domande che dovremmo porci o problemi dovrei essere a conoscenza se voglio usare tubi in questo modo?

E 'tutto ciò che si vuole fare davvero intenzione di tracciare una linea come questa? In caso contrario, si potrebbe desiderare di pensare a un'architettura più generale. Ma l'intuizione che avere un sacco di processi separati che interagiscono attraverso l'interfaccia "stretta" di un tubo è auspicabile è un buon compromesso.

[Aggiornamento: Ho avuto gli indici descrittore di file invertiti in un primo momento. Loro sono corretto ora, vedere man 2 pipe.]

Come hanno notato anche Dashogun e Charlie Martin, questa è una grande domanda. Alcune parti delle loro risposte sono imprecise, così ho intenzione di rispondere anche.

  

Sono interessato a scrivere moduli di programma separati che funzionano fili indipendenti da poter agganciare insieme con i tubi.

Diffidare di tentare di utilizzare tubi come un meccanismo di comunicazione tra i thread di un unico processo. Perché si dovrebbe leggere e scrivere estremità del tubo aperto in un unico processo, non si sarebbe mai ottenere l'indicazione EOF (zero byte).

Se si dovesse davvero riferisce a processi, allora questa è la base dell'approccio classico Unix per strumenti di costruzione. Molti dei programmi standard Unix sono filtri che leggono dallo standard input, lo trasformano in qualche modo, e scrivono il risultato sullo standard output. Ad esempio, tr, sort, grep, e cat sono tutti i filtri, per citarne solo alcuni. Questo è un ottimo paradigma da seguire quando i dati che si stanno manipolando lo permette. Non tutte le manipolazioni di dati sono favorevoli a questo approccio, ma ci sono molti che sono.

  

La motivazione sarebbe che ho potuto scrivere e testare ogni modulo completamente indipendente, forse persino scrivere in lingue diverse, o eseguire i diversi moduli su macchine diverse.

I punti positivi. Essere consapevoli del fatto che in realtà non c'è un meccanismo di pipe tra le macchine, anche se è possibile avvicinarsi ad essa con programmi come rsh o (meglio) ssh. Tuttavia, internamente, questi programmi possono leggere i dati locali da tubi e inviare i dati al computer remoti, ma comunicano tra macchine oltre i socket, non utilizzando tubi.

  

Ci sono una vasta gamma di possibilità. Ho usato tubazioni per un po ', ma io sono familiarità con le sfumature del suo comportamento.

OK; porre domande è un modo (buono) per imparare. Sperimentare è un altro, ovviamente.

  

Sembra che alla fine di ricezione bloccherà in attesa di input, che mi sarei aspettato, ma la testata di invio a volte in attesa che qualcuno a leggere dal flusso?

Sì. V'è un limite alla dimensione di un buffer tubo. Classicamente, questo era piuttosto piccola - 4096 o 5120 erano valori comuni. Potreste scoprire che moderna Linux utilizza un valore maggiore. È possibile utilizzare fpathconf() e _PC_PIPE_BUF di scoprire la dimensione di un buffer pipe. POSIX richiede solo buffer per essere 512 (cioè, _POSIX_PIPE_BUF è 512).

  

Se scrivo un EOF al flusso posso continuare a continuare a scrivere a quel flusso fino a quando io lo chiudo?

Tecnicamente, non c'è modo di scrivere EOF in un flusso; si chiude il descrittore del tubo per indicare EOF. Se state pensando di control-D o il controllo-Z come un carattere EOF, quindi questi sono i personaggi appena regolari per quanto riguarda i tubi sono preoccupati - hanno solo un effetto come EOF se digitato da un terminale che è in esecuzione in modalità canonica (cotto , o normale).

  

Ci sono differenze nel comportamento di nome e tubi senza nome?

Sì e no. Le maggiori differenze sono che i tubi senza nome devono essere impostate da un processo e può essere utilizzato solo da quel processo ed i bambini che condividono questo processo come un antenato comune. Al contrario, le named pipe possono essere utilizzati da processi in precedenza non associati. Il prossimo grande differenza è una conseguenza della prima; con un tubo senza nome, si ottiene indietro di due descrittori di file da una singola funzione (sistema) chiamata per pipe(), ma si apre un FIFO o named pipe utilizzando la funzione di regolare open(). (Qualcuno deve creare una FIFO con il mkfifo() chiamata prima di poter aprire; pipe senza nome non hanno bisogno di tale configurazione precedente.) Tuttavia, una volta che si dispone di un descrittore di file aperto, v'è ben poco differenza tra una named pipe e di una unnamed pipe.

  

È importante l'estremità del tubo apro prima con named pipe?

No. I primi process per aprire il FIFO sarà (normalmente) bloccare finché esiste un processo con l'altra estremità aperta. Se lo si apre per la lettura e la scrittura (aconventional ma possibile), allora non sarà bloccato; se si utilizza il flag O_NONBLOCK, non sarà bloccato.

  

è il comportamento dei tubi coerenti tra i diversi sistemi Linux?

Sì. Io non ho sentito o sperimentato problemi con i tubi su uno qualsiasi dei sistemi in cui io li ho usato.

  

Fa il comportamento dei tubi dipende dalla shell che sto utilizzando o il modo in cui ho configurato esso?

No: tubi e FIFO sono indipendenti del guscio si utilizza

.
  

Ci sono altre domande che dovremmo porci o problemi dovrei essere a conoscenza se voglio usare tubi in questo modo?

Basta ricordare che è necessario chiudere alla fine la lettura di un tubo nel processo che verrà scritto, e la fine di scrittura del tubo nel processo che sarà la lettura. Se si desidera che la comunicazione bidirezionale tramite tubi, utilizzare due tubi separati. Se si creano accordi idraulici complicati, fate attenzione di stallo - è possibile. Una conduttura lineare non deadlock, tuttavia (anche se il primo processo non chiude la sua uscita, i processi a valle possono aspettare indefinitamente).


ho osservato sia sopra che nei commenti ad altre risposte che i buffer dei tubi sono classicamente limitati a molto piccole dimensioni. @Charlie Martin contro-commentato che alcune versioni di Unix hanno buffer pipe dinamiche e questi possono essere abbastanza grandi.

Non sono sicuro di quali egli ha in mente. Ho usato il programma di test che segue su Solaris, AIX, HP-UX, MacOS X, Linux e Cygwin / Windows XP (risultati qui sotto):

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

static const char *arg0;

static void err_syserr(char *str)
{
    int errnum = errno;
    fprintf(stderr, "%s: %s - (%d) %s\n", arg0, str, errnum, strerror(errnum));
    exit(1);
}

int main(int argc, char **argv)
{
    int pd[2];
    pid_t kid;
    size_t i = 0;
    char buffer[2] = "a";
    int flags;

    arg0 = argv[0];

    if (pipe(pd) != 0)
        err_syserr("pipe() failed");
    if ((kid = fork()) < 0)
        err_syserr("fork() failed");
    else if (kid == 0)
    {
        close(pd[1]);
        pause();
    }
    /* else */
    close(pd[0]);
    if (fcntl(pd[1], F_GETFL, &flags) == -1)
        err_syserr("fcntl(F_GETFL) failed");
    flags |= O_NONBLOCK;
    if (fcntl(pd[1], F_SETFL, &flags) == -1)
        err_syserr("fcntl(F_SETFL) failed");
    while (write(pd[1], buffer, sizeof(buffer)-1) == sizeof(buffer)-1)
    {
        putchar('.');
        if (++i % 50 ==  0)
            printf("%u\n", (unsigned)i);
    }
    if (i % 50 !=  0)
        printf("%u\n", (unsigned)i);
    kill(kid, SIGINT);
    return 0;
}

Sarei curioso di ottenere risultati in più da altre piattaforme. Qui ci sono le dimensioni che ho trovato. Tutti i risultati sono più grandi di quanto mi aspettassi, lo confesso, ma Charlie e io sia il discutere il significato di 'abbastanza grande' quando si tratta di tamponare le dimensioni.

  • 8196 - HP-UX 11.23 per IA-64 (fcntl (F_SETFL) non)
  • 16384 - Solaris 10
  • 16384 - MacOS X 10.5 (O_NONBLOCK non ha funzionato, anche se fcntl (F_SETFL) non ha mancato)
  • 32768 - AIX 5.3
  • 65536 - Cygwin / Windows XP (O_NONBLOCK non ha funzionato, anche se fcntl (F_SETFL) non ha mancato)
  • 65536 - SuSE Linux 10 (e CentOS) (fcntl (F_SETFL) non)

Un punto che è chiaro da questi test è che O_NONBLOCK lavora con tubi su alcune piattaforme e non su altri.

Il programma crea una pipa, e forcelle. Il bambino si chiude alla fine di scrittura del tubo, e poi va a dormire fino a quando non riceve un segnale - questo è ciò che di pausa () fa. Il genitore quindi chiude l'estremità lettura del tubo, e imposta i flag sul descrittore scrittura in modo che non blocca il tentativo di scrivere su un tubo pieno. E poi loop, la scrittura di un carattere alla volta, e la stampa di un punto per ogni carattere scritto, e un conteggio e ritorno a capo ogni 50 caratteri. Quando rileva un problema di scrittura (buffer pieno, dal momento che il bambino non sta leggendo una cosa), si ferma il ciclo, scrive il conteggio finale, e uccide il bambino.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top