From 52958c279452903b8c4edea25643096a32c67235 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 28 Jul 2002 11:13:45 +0000 Subject: [PATCH] Correzioni --- fileadv.tex | 2 - ipc.tex | 152 +++++++++++++++++++++++++++------------------------- 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index b4e658b..578f867 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -373,8 +373,6 @@ invier in eccesso, e si dovrà determinare al solito modo quali sono i file diventati attivi. - - Benché la modalità di apertura asincrona di un file possa risultare utile in varie occasioni (in particolar modo con i socket e gli altri file per i quali le funzioni di I/O sono system call lente), essa è comunque limitata alla diff --git a/ipc.tex b/ipc.tex index 03bc5e7..e0fef63 100644 --- a/ipc.tex +++ b/ipc.tex @@ -20,12 +20,11 @@ implementati con un ulteriore livello sopra i meccanismi elementari. \section{La comunicazione fra processi tradizionale} \label{sec:ipc_unix} -Il primo meccanismo di comunicazione fra processi usato dai sistemi unix-like, -e quello che viene correntemente usato di più, è quello delle \textit{pipe}, -che sono una delle caratteristiche peculiari del sistema, in particolar modo -dell'interfaccia a linea di comando. In questa sezione descriveremo le sue -basi, le funzioni che ne gestiscono l'uso e le varie forme in cui si è -evoluto. +Il primo meccanismo di comunicazione fra processi introdotto nei sistemi Unix, +è quello delle cosiddette \textit{pipe}; esse costituiscono una delle +caratteristiche peculiari del sistema, in particolar modo dell'interfaccia a +linea di comando. In questa sezione descriveremo le sue basi, le funzioni che +ne gestiscono l'uso e le varie forme in cui si è evoluto. \subsection{Le \textit{pipe} standard} @@ -33,39 +32,36 @@ evoluto. Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e tuttora uno dei più usati, meccanismi di comunicazione fra processi. Si tratta in -sostanza di uno speciale tipo di file descriptor, più precisamente una coppia -di file descriptor,\footnote{si tenga presente che le pipe sono oggetti creati - dal kernel e non risiedono su disco.} su cui da una parte si scrive e da -un'altra si legge. Si viene così a costituire un canale di comunicazione -tramite i due file descriptor, nella forma di un \textsl{tubo} (da cui il -nome) in cui in genere un processo immette dati che poi arriveranno ad un -altro. - -La funzione che permette di creare una pipe è appunto \func{pipe}; il suo -prototipo è: +sostanza di una una coppia di file descriptor\footnote{si tenga presente che + le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi +fra di loro in modo che se quanto scrive su di uno si può rileggere +dall'altro. Si viene così a costituire un canale di comunicazione tramite i +due file descriptor, nella forma di un \textsl{tubo} (da cui il nome) +attraverso cui fluiscono i dati. + +La funzione che permette di creare questa speciale coppia di file descriptor +associati ad una \textit{pipe} è appunto \func{pipe}, ed il suo prototipo è: \begin{prototype}{unistd.h} {int pipe(int filedes[2])} -Crea una coppia di file descriptor associati ad una pipe. +Crea una coppia di file descriptor associati ad una \textit{pipe}. \bodydesc{La funzione restituisce zero in caso di successo e -1 per un errore, nel qual caso \var{errno} potrà assumere i valori \macro{EMFILE}, \macro{ENFILE} e \macro{EFAULT}.} \end{prototype} -La funzione restituisce una coppia di file descriptor nell'array -\param{filedes}; il primo aperto in lettura ed il secondo in scrittura. Il -concetto di funzionamento di una pipe è relativamente semplice, quello che si +La funzione restituisce la coppia di file descriptor nell'array +\param{filedes}; il primo è aperto in lettura ed il secondo in scrittura. Come +accennato concetto di funzionamento di una pipe è semplice: quello che si scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale -nel file descriptor aperto in lettura, da cui può essere riletto. - -I file descriptor infatti non sono connessi a nessun file reale, ma ad un -buffer nel kernel, la cui dimensione è specificata dalla costante -\macro{PIPE\_BUF}, (vedi \secref{sec:sys_file_limits}); lo schema di -funzionamento di una pipe è illustrato in \figref{fig:ipc_pipe_singular}, in -cui sono illustrati i due capi della pipe, associati a ciascun file -descriptor, con le frecce che indicano la direzione del flusso dei dati -attraverso la pipe. +nel file descriptor aperto in lettura. I file descriptor infatti non sono +connessi a nessun file reale, ma ad un buffer nel kernel, la cui dimensione è +specificata dalla costante \macro{PIPE\_BUF}, (vedi +\secref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è +illustrato in \figref{fig:ipc_pipe_singular}, in cui sono illustrati i due +capi della pipe, associati a ciascun file descriptor, con le frecce che +indicano la direzione del flusso dei dati. \begin{figure}[htb] \centering @@ -74,12 +70,12 @@ attraverso la pipe. \label{fig:ipc_pipe_singular} \end{figure} -Chiaramente creare una pipe all'interno di un processo non serve a niente; se -però ricordiamo quanto esposto in \secref{sec:file_sharing} riguardo al -comportamento dei file descriptor nei processi figli, è immediato capire come -una pipe possa diventare un meccanismo di intercomunicazione. Un processo -figlio infatti condivide gli stessi file descriptor del padre, compresi quelli -associati ad una pipe (secondo la situazione illustrata in +Chiaramente creare una pipe all'interno di un singolo processo non serve a +niente; se però ricordiamo quanto esposto in \secref{sec:file_sharing} +riguardo al comportamento dei file descriptor nei processi figli, è immediato +capire come una pipe possa diventare un meccanismo di intercomunicazione. Un +processo figlio infatti condivide gli stessi file descriptor del padre, +compresi quelli associati ad una pipe (secondo la situazione illustrata in \figref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un capo della pipe, l'altro può leggere. @@ -92,16 +88,16 @@ capo della pipe, l'altro pu \end{figure} Tutto ciò ci mostra come sia immediato realizzare un meccanismo di -comunicazione fra processi attraverso una pipe, utilizzando le ordinarie -proprietà dei file, ma ci mostra anche qual'è il principale\footnote{Stevens +comunicazione fra processi attraverso una pipe, utilizzando le proprietà +ordinarie dei file, ma ci mostra anche qual'è il principale\footnote{Stevens in \cite{APUE} riporta come limite anche il fatto che la comunicazione è - unidirezionale, in realtà questo è un limite facilmente superabile usando + unidirezionale, ma in realtà questo è un limite facilmente superabile usando una coppia di pipe.} limite nell'uso delle pipe. È necessario infatti che i 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. +devono comunque derivare da uno stesso processo padre in cui è avvenuta la +creazione della pipe, o, più comunemente, essere nella relazione padre/figlio. -A differenza di quanto avviene con i file normali la lettura da una pipe può +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 @@ -122,14 +118,14 @@ da altri processi. \subsection{Un esempio dell'uso delle pipe} \label{sec:ipc_pipe_use} -Per capire meglio il funzionamento di una pipe faremo un esempio di quello che +Per capire meglio il funzionamento delle pipe faremo un esempio di quello che è il loro uso più comune, analogo a quello effettuato della shell, e che consiste nell'inviare l'output di un processo (lo standard output) sull'input -di un'altro. Realizzeremo il programma nella forma di un -\textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface}) è un programma - che permette la creazione dinamica di un oggetto da inserire all'interno di - una pagina HTML.} per apache, che genera una immagine JPEG di un codice a -barre, specificato come parametro di input. +di un'altro. Realizzeremo il programma di esempio nella forma di un +\textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface}) è un + programma che permette la creazione dinamica di un oggetto da inserire + all'interno di una pagina HTML.} per apache, che genera una immagine JPEG +di un codice a barre, specificato come parametro di input. Un programma che deve essere eseguito come \textit{CGI} deve rispondere a delle caratteristiche specifiche, esso infatti non viene lanciato da una @@ -143,13 +139,13 @@ che ne descrive il mime-type) sullo standard output, in modo che il web-server possa reinviarlo al browser che ha effettuato la richiesta, che in questo modo è in grado di visualizzarlo opportunamente. -Per fare questo useremo in sequenza i programmi \cmd{barcode} e \cmd{gs}, il -primo infatti è in grado di generare immagini postscript di codici a barre -corrispondenti ad una qualunque stringa, mentre il secondo serve per poter -effettuare la conversione della stessa immagine in formato JPEG. Usando una -pipe potremo inviare l'output del primo sull'input del secondo, secondo lo -schema mostrato in \figref{fig:ipc_pipe_use}, in cui la direzione del flusso -dei dati è data dalle frecce continue. +Per realizzare quanto voluto useremo in sequenza i programmi \cmd{barcode} e +\cmd{gs}, il primo infatti è in grado di generare immagini postscript di +codici a barre corrispondenti ad una qualunque stringa, mentre il secondo +serve per poter effettuare la conversione della stessa immagine in formato +JPEG. Usando una pipe potremo inviare l'output del primo sull'input del +secondo, secondo lo schema mostrato in \figref{fig:ipc_pipe_use}, in cui la +direzione del flusso dei dati è data dalle frecce continue. \begin{figure}[htb] \centering @@ -554,7 +550,7 @@ processo alla volta (nel qual caso basta usare due pipe, una per leggere ed una per scrivere), le cose diventano invece molto più complesse quando si vuole effettuare una comunicazione fra il server ed un numero imprecisato di client; se il primo infatti può ricevere le richieste attraverso una fifo -``nota'', per le risposte non si può fare altrettanto, dato che per la +``nota'', per le risposte non si può fare altrettanto, dato che, per la struttura sequenziale delle fifo, i client dovrebbero sapere, prima di leggerli, quando i dati inviati sono destinati a loro. @@ -581,40 +577,48 @@ comunicazione, come quelli che esamineremo in \secref{sec:ipc_sysv}. 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; per cui una situazione in cui un processo scrive +è rigidamente sequenziale; per questo una situazione in cui un processo scrive qualcosa che molti altri devono poter leggere non può essere implementata in maniera semplice con una pipe. -Per superarne questi limiti nello sviluppo di System V vennero introdotti una +Per superare questi limiti nello sviluppo di System V vennero introdotti una serie di nuovi oggetti di comunicazione e relative interfacce di -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)}. +programmazione in grado di garantire una maggiore flessibilità; in questa +sezione esamineremo quello che viene ormai chiamato il \textsl{Sistema di + comunicazione inter-processo} di System V, (o \textit{System V IPC + (Inter-Process Comunication)}. \subsection{Considerazioni generali} \label{sec:ipc_sysv_generic} -La principale caratteristica, (che può essere considerato anche uno dei suoi -maggiori difetti) del sistema di IPC di System V è che è basato su oggetti che -risiedono nel kernel, a differenza delle pipe che sono locali ai processi che -condividono lo stesso file descriptor, e delle fifo, cui invece si accede -attraverso il filesystem. - -Ad essi si accede attraverso un identificatore generato autonomamente dal -kernel alla loro creazione (come un numero intero progressivo, in maniera -simile a quanto fatto per i \acr{pid}). A ciascun oggetto è pure associata una -chiave, che di norma viene usata per ricavare l'identificatore. - -Una seconda caratteristica di questi oggetti è che non prevedono un numero di +La principale caratteristica del sistema di IPC di System V è quella di essere +basato su oggetti permanenti che risiedono nel kernel. Questi, a differenza di +quanto avviene per i file descriptor, non mantengono un contatore dei +riferimenti, pertanto non vengono cancellati dal sistema una volta che non +sono più in uso. Questo comporta che, al contrario di quanto avviene per pipe +e fifo, la memoria allocata per questi oggetti non viene rilasciata +automaticamente, ed essi devono essere cancellati esplicitamente, altrimenti +resteranno attivi fintanto che non si riavvia il sistema. +Gli oggetti usati nel System V IPC vengono creati direttamente dal kernel, e +sono accessibili solo specificando il relativo \textsl{identificatore}, che è +il numero progressivo che il kernel gli assengna quanto vengono creati (il +prodedimento è simile a quello con cui si assegna il \acr{pid} dei processi). +L'identificatore è in genere restituito dalle funzioni che creano l'oggetto, +nasce quindi il problema di come processi diversi possono accedere allo stesso +oggetto. Per far questo a ciascuno di essi viene anche associata una +\textsl{chiave}, che può essere indicata in fasi di creazione. Usando la +stessa chiave due processi diversi potranno ricavare l'identificatore +associato ad un oggetto e accedervi entrambi. +Questa caratteristica mostra il primo dei problemi associati al sistema di IPC +di System V. Un secondo problema riguarda le modalità per l'accesso a questi +oggetti. - \subsection{Code di messaggi} \label{sec:ipc_messque} -- 2.30.2