X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=bdbdf2c13d9068e85617b49f2ff16cc321cf416e;hp=3c30111cebf747b7316715bdcc672a4e373b441c;hb=81ff87c3e2a6ecd3e33867798cba0d27576f44d0;hpb=f554a11afa7c50c2b0267e890fb7581b6605384d diff --git a/ipc.tex b/ipc.tex index 3c30111..bdbdf2c 100644 --- a/ipc.tex +++ b/ipc.tex @@ -101,6 +101,23 @@ processi possano condividere i file descriptor della pipe, e per questo essi devono comunque derivare da uno stesso processo padre che ha aperto la pipe, o, più comunemente, essere nella relazione padre/figlio. +A differenza di quanto avviene con i file normali la lettura da una pipe può +essere bloccante (qualora non siano presenti dati), inoltre se si legge da una +pipe il cui capo in scrittura è stato chiuso, si avrà la ricezione di un EOF +(vale a dire che la funzione \func{read} ritornerà restituendo 0). Se invece +si esegue una scrittura su una pipe il cui capo in lettura non è aperto il +processo riceverà il segnale \macro{EPIPE}, e la funzione di scrittura +restituirà un errore di \macro{EPIPE} (al ritorno del manipolatore, o qualora +il segnale sia ignorato o bloccato). + +La dimensione del buffer della pipe (\macro{PIPE\_BUF}) ci dà inoltre un'altra +importante informazione riguardo il comportamento delle operazioni di lettura +e scrittura su di una pipe; esse infatti sono atomiche fintanto che la +quantità di dati da scrivere non supera questa dimensione. Qualora ad esempio +si effettui una scrittura di una quantità di dati superiore l'operazione verrà +effettuata in più riprese, consentendo l'intromissione di scritture effettuate +da altri processi. + \subsection{Un esempio dell'uso delle pipe} \label{sec:ipc_pipe_use} @@ -148,7 +165,7 @@ intermedio su un file temporaneo. Questo per \textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una evidente race condition in caso di accesso simultaneo a detto file.\footnote{il problema potrebbe essere superato determinando in anticipo - un nome appropiato per il file temporaneo, che verrebbe utilizzato dai vari + un nome appropriato per il file temporaneo, che verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della loro esecuzione; ma a questo le cose non sarebbero più tanto semplici.} L'uso di una pipe invece permette di risolvere il problema in maniera semplice ed elegante. @@ -158,8 +175,8 @@ duplicazione dei file descriptor che abbiamo trattato in \secref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste funzioni infatti che è possibile dirottare gli stream standard dei processi (che abbiamo visto in \secref{sec:file_std_descr} e -\secref{sec:file_std_stream}) sulla pipe. In \figref{fig:ipc_barcode_code} -abbiamo riportato il corpo del programm, il cui codice completo è disponibile +\secref{sec:file_std_stream}) sulla pipe. In \figref{fig:ipc_barcodepage_code} +abbiamo riportato il corpo del programma, il cui codice completo è disponibile nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti. @@ -219,7 +236,7 @@ int main(int argc, char *argv[], char *envp[]) \normalsize \caption{Sezione principale del codice del \textit{CGI} \file{BarCodePage.c}.} - \label{fig:ipc_barcode_code} + \label{fig:ipc_barcodepage_code} \end{figure} La prima operazione del programma (\texttt{\small 4--12}) è quella di creare @@ -227,10 +244,10 @@ le due pipe che serviranno per la comunicazione fra i due comandi utilizzati per produrre il codice a barre; si ha cura di controllare la riuscita della chiamata, inviando in caso di errore un messaggio invece dell'immagine richiesta.\footnote{la funzione \func{WriteMess}, non è riportata in - \secref{fig:ipc_barcode_code}; essa si incarica semplicemente di formattare - l'uscita alla maniera dei CGI, aggiungendo l'opportuno \textit{mime type}, e - formattando il messaggio in HTML, in modo che quest'ultimo possa essere - visualizzato correttamente da un browser.} + \secref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di + formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno + \textit{mime type}, e formattando il messaggio in HTML, in modo che + quest'ultimo possa essere visualizzato correttamente da un browser.} Una volta create le pipe, il programma può creare (\texttt{\small 13-17}) il primo processo figlio, che si incaricherà (\texttt{\small 19--25}) di eseguire @@ -285,7 +302,7 @@ capo in scrittura della seconda pipe, e attende la conclusione del figlio (\texttt{\small 45}); a questo punto può (\texttt{\small 46}) uscire. Si tenga conto che l'operazione di chiudere il capo in scrittura della seconda pipe è necessaria, infatti, se non venisse chiusa, \cmd{gs}, che legge il suo -stardard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati +standard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati in ingresso (l'unico modo che un programma ha per sapere che l'input è terminato è rilevare che lo standard input è stato chiuso), e la \func{wait} non ritornerebbe. @@ -332,7 +349,7 @@ funzioni, \func{pclose}, il cui prototipo \begin{prototype}{stdio.h} {int pclose(FILE *stream)} -Chiude il file \param{stream}, restituito da una prededente \func{popen} +Chiude il file \param{stream}, restituito da una precedente \func{popen} attendendo la terminazione del processo ad essa associato. \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di @@ -344,8 +361,8 @@ attendendo la terminazione del processo ad essa associato. \func{popen}. Per illustrare l'uso di queste due funzioni riprendiamo il problema -precedente: il programma mostrato in \figref{fig:ipc_barcode_code} per quanto -funzionante, è (volutamente) codificato in maniera piuttosto complessa, +precedente: il programma mostrato in \figref{fig:ipc_barcodepage_code} per +quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa, inoltre nella pratica sconta un problema di \cmd{gs} che non è in grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di riconoscere correttamente l'encapsulated postscript, per cui deve essere usato @@ -380,19 +397,19 @@ dimensioni corrette attraverso vari programmi di manipolazione (\cmd{pnmcrop}, In questo caso però occorre eseguire in sequenza ben quattro comandi diversi, inviando l'output di ciascuno all'input del successivo, per poi ottenere il -risultato finale sullo standard output; un caso classico di utilizzazione +risultato finale sullo standard output: un caso classico di utilizzazione delle pipe, in cui l'uso di \func{popen} e \func{pclose} permette di semplificare notevolmente la stesura del codice. Nel nostro caso, dato che ciascun processo deve scrivere il suo output sullo standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in scrittura. Il codice del nuovo programma è riportato in -\figref{fig:ipc_barcode2_code}. Come si può notare l'ordine di invocazione -dei programmi è l'inverso di quello in cui ci si aspetta vengano -effettivamente eseguiti. Questo non comporta nessun problema; infatti la +\figref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione dei +programmi è l'inverso di quello in cui ci si aspetta che vengano +effettivamente eseguiti. Questo non comporta nessun problema dato che la lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato per primo, si bloccherà in attesa di ricevere sullo standard input il -risultato dell'elaborazione del precendente, benchè quest'ultimo venga +risultato dell'elaborazione del precedente, benchè quest'ultimo venga invocato dopo. \begin{figure}[!htb] @@ -427,12 +444,6 @@ int main(int argc, char *argv[], char *envp[]) pclose((pipe[i])); } exit(0); -} -void WriteMess(char *mess) -{ - printf("Content-type: text/html\n\n"); - perror(mess); - printf("
\n"); } \end{lstlisting} \end{minipage} @@ -472,61 +483,80 @@ Come accennato in \secref{sec:ipc_pipes} il problema delle \textit{pipe} esse possono essere utilizzate solo da processi con un progenitore comune o nella relazione padre/figlio; per superare questo problema lo standard POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse -caratteristiche delle pipe, ma invece che essere struttura interne del kernel -visibili solo attraverso un file descriptor comune, possono essere viste -attraverso un inode che risiede sul filesystem. - -Utilizzando una fifo tutti i dati passeranno attraverso un apposito buffer nel -kernel, senza transitare dal filesystem, l'inode serve solo a fornire un punto -d'appoggio per i vari processi che permetta loro di accedere alla stessa -fifo. - - - - -Abbiamo già visto in \secref{sec:file_mknod} le modalità che permettono di -creare una fifo, attraverso le funzioni \func{mknod} e \func{mkfifo}; per -utilizzarle un processo non avrà che da aprire il relativo file in lettura o -scrittura (a seconda della direzione che si vuole dare ai dati). - -che invece possono risiedere -sul filesystem, e che i processi possono usare per le comunicazioni senza -dovere per forza essere in relazione diretta. - - +caratteristiche delle pipe, ma che invece di essere strutture interne del +kernel, visibili solo attraverso un file descriptor, sono accessibili +attraverso un inode che risiede sul filesystem, così che i processi le possono +usare senza dovere per forza essere in una relazione di \textsl{parentela}. + +Utilizzando una \textit{fifo} tutti i dati passeranno, come per le pipe, +attraverso un apposito buffer nel kernel, senza transitare dal filesystem; +l'inode allocato sul filesystem serve infatti solo a fornire un punto di +riferimento per i processi, che permetta loro di accedere alla stessa fifo; il +comportamento delle funzioni di lettura e scrittura è identico a quello +illustrato per le pipe in \secref{sec:ipc_pipes}. + +Abbiamo già visto in \secref{sec:file_mknod} le funzioni \func{mknod} e +\func{mkfifo} che permettono di creare una fifo; per utilizzarne una un +processo non avrà che da aprire il relativo file speciale o in lettura o +scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà +leggere, nel secondo al capo di ingresso, e dovrà scrivere. + +Il kernel crea una singola pipe per ciascuna fifo che sia stata aperta, che può +essere acceduta contemporaneamente da più processi, sia in lettura che in +scrittura. Dato che per funzionare deve essere aperta in entrambe le +direzioni, per una fifo di norma la funzione \func{open} si blocca se viene +eseguita quando l'altro capo non è aperto. + +Le fifo però possono essere anche aperte in modalità \textsl{non-bloccante}, +nel qual caso l'apertura del capo in lettura avrà successo solo quando anche +l'altro capo è aperto, mentre l'apertura del capo in scrittura restituirà +l'errore di \macro{ENXIO} fintanto che non verrà aperto il capo in lettura. + +In Linux\footnote{lo standard POSIX lascia indefinito questo comportamento.} è +possibile aprire le fifo anche in lettura/scrittura, operazione che avrà +sempre successo immediato qualunque sia la modalità di apertura (bloccante e +non bloccante); questo può essere utilizzato per aprire comunque una fifo in +scrittura anche se non ci sono ancora processi il lettura; è possibile anche +usare la fifo all'interno di un solo processo, nel qual caso però occorre +stare molto attenti alla possibili deadlock.\footnote{se si cerca di leggere + da una fifo che non contiene dati si avrà un deadlock immediato, dato che il + processo si blocca e non potrà quindi mai eseguire le funzioni di + scrittura.} -Per poter superare il problema delle \textit{pipe}, illustrato in -\secref{sec:ipc_pipes}, che ne consente l'uso solo fra processi con un -progenitore comune o nella relazione padre/figlio, \section{La comunicazione fra processi di System V} \label{sec:ipc_sysv} -Per ovviare ai vari limiti dei meccanismo tradizionale di comunicazione fra -processi visto in \secref{sec:ipc_unix}, nello sviluppo di System V vennero -introdotti una serie di nuovi oggetti e relative interfacce che garantissero -una maggiore flessibilità; in questa sezione esamineremo quello che viene -ormai chiamato il \textit{System V Inter-Process Comunication System}, più -comunemente noto come \textit{SystemV IPC}. +Benché le pipe (e le fifo) siano ancora ampiamente usate, esse presentano +numerosi limiti, il principale dei quali è che il meccanismo di comunicazione +è rigidamente sequenziale; una situazione in cui un processo scrive qualcosa +che molti altri devono poter leggere non può essere implementata con una pipe. + +Per superarne i vari limiti, nello sviluppo di System V vennero introdotti una +serie di nuovi oggetti di comunicazione e relative interfacce id +programmazione che garantissero una maggiore flessibilità; in questa sezione +esamineremo quello che viene ormai chiamato il \textsl{Sistema di + comunicazione inter-processo} di System V , più comunemente noto come +\textit{System V IPC (Inter-Process Comunication)}. \subsection{Code di messaggi} \label{sec:ipc_messque} -Il primo oggetto introdotto dal \textit{SystemV IPC} è quello delle code di +Il primo oggetto introdotto dal \textit{System V IPC} è quello delle code di messaggi. \subsection{Semafori} \label{sec:ipc_semaph} -Il secondo oggetto introdotto dal \textit{SystemV IPC} è quello dei semafori. +Il secondo oggetto introdotto dal \textit{System V IPC} è quello dei semafori. \subsection{Memoria condivisa} \label{sec:ipc_shar_mem} -Il terzo oggetto introdotto dal \textit{SystemV IPC} è quello della memoria +Il terzo oggetto introdotto dal \textit{System V IPC} è quello della memoria condivisa. %%% Local Variables: