Risistemati ed insiriti nella relativa sezione gli esempi di uso dei
authorSimone Piccardi <piccardi@gnulinux.it>
Fri, 31 Dec 2010 13:30:45 +0000 (13:30 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Fri, 31 Dec 2010 13:30:45 +0000 (13:30 +0000)
segmenti di memoria condivisa e dei semafori POSIX.

ipc.tex
listati/HandSigInt.c [new file with mode: 0644]
listati/message_getter.c [new file with mode: 0644]
listati/message_setter.c [new file with mode: 0644]
sources/message_getter.c
sources/message_setter.c

diff --git a/ipc.tex b/ipc.tex
index 69286e92a16ed2d0925c76840628c03c7735465d..d22c3ba381bcab3aadcce723e927fef2a43c28f0 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -3758,11 +3758,11 @@ registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore
 del segnale di notifica. A differenza della situazione simile che si aveva con
 i segnali non affidabili,\footnote{l'argomento è stato affrontato in
   \ref{sec:sig_semantics}.} questa caratteristica non configura una
-race-condition perché l'invio di un segnale avviene solo se la coda è vuota;
-pertanto se si vuole evitare di correre il rischio di perdere eventuali
-ulteriori segnali inviati nel lasso di tempo che occorre per ripetere la
-richiesta di notifica basta avere cura di eseguire questa operazione prima di
-estrarre i messaggi presenti dalla coda.
+\itindex{race~condition} \textit{race condition} perché l'invio di un segnale
+avviene solo se la coda è vuota; pertanto se si vuole evitare di correre il
+rischio di perdere eventuali ulteriori segnali inviati nel lasso di tempo che
+occorre per ripetere la richiesta di notifica basta avere cura di eseguire
+questa operazione prima di estrarre i messaggi presenti dalla coda.
 
 L'invio del segnale di notifica avvalora alcuni campi di informazione
 restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in
@@ -4393,13 +4393,179 @@ dall'altro programma prima di averla finita di stampare.
 La parte iniziale del programma contiene le definizioni (\texttt{\small 1--8})
 del gestore del segnale usato per liberare le risorse utilizzate, delle
 variabili globali contenenti i nomi di default del segmento di memoria
-condivisa e del semaforo, e delle altre variabili utilizzate dal programma.
+condivisa e del semaforo (il default scelto è \texttt{messages}), e delle
+altre variabili utilizzate dal programma.
 
 Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un
-gestore di segnale che consentirà di effettuare le operazioni di pulizia, dopo
-di che 
+gestore di segnale che consentirà di effettuare le operazioni di pulizia
+(usando la funzione \func{Signal} illustrata in
+fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 10--16}) si è
+creato il segmento di memoria condivisa con la funzione \func{CreateShm} che
+abbiamo appena trattato in sez.~\ref{sec:ipc_posix_shm}, uscendo con un
+messaggio in caso di errore. 
+
+Si tenga presente che la funzione \func{CreateShm} richiede che il segmento
+non sia già presente e fallirà qualora un'altra istanza, o un altro programma
+abbia già allocato un segmento con quello stesso nome. Per semplicità di
+gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la
+costante \texttt{MSGMAXSIZE}.
+
+Il passo successivo (\texttt{\small 17--21}) è quello della creazione del
+semaforo che regola l'accesso al segmento di memoria condivisa con
+\func{sem\_open}; anche in questo caso si gestisce l'uscita con stampa di un
+messaggio in caso di errore. Anche per il semaforo, avendo specificato la
+combinazione di flag \code{O\_CREAT|O\_EXCL} come secondo argomento, si esce
+qualora fosse già esistente; altrimenti esso verrà creato con gli opportuni
+permessi specificati dal terzo argomento, (indicante lettura e scrittura in
+notazione ottale). Infine il semaforo verrà inizializzato ad un valore nullo
+(il quarto argomento), corrispondete allo stato in cui risulta bloccato.
+
+A questo punto (\texttt{\small 23}) si potrà inizializzare il messaggio posto
+nel segmento di memoria condivisa usando la stringa passata come argomento al
+programma. Essendo il semaforo stato creato già bloccato non ci si dovrà
+preoccupare di eventuali \itindex{race~condition} \textit{race condition}
+qualora il programma di modifica del messaggio venisse lanciato proprio in
+questo momento.  Una volta inizializzato il messaggio occorrerà però
+rilasciare il semaforo (\texttt{\small 25--28}) per consentirne l'uso; in
+tutte queste operazioni si provvederà ad uscire dal programma con un opportuno
+messaggio in caso di errore.
+
+Una volta completate le inizializzazioni il ciclo principale del programma
+(\texttt{\small 29--47}) viene ripetuto indefinitamente (\texttt{\small 29})
+per stampare sia il contenuto del messaggio che una serie di informazioni di
+controllo. Il primo passo (\texttt{\small 30--34}) è quello di acquisire (con
+\func{sem\_getvalue}, con uscita in caso di errore) e stampare il valore del
+semaforo ad inizio del ciclo; seguito (\texttt{\small 35--36}) dal tempo
+corrente.
 
+\begin{figure}[!h]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/HandSigInt.c}
+  \end{minipage} 
+  \normalsize 
+  \caption{Codice del gestore di segnale del programma
+    \file{message\_getter.c}.}
+  \label{fig:ipc_posix_sem_shm_message_server_handler}
+\end{figure}
+
+Prima della stampa del messaggio invece si deve aquisire il semaforo
+(\texttt{\small 31--34}) per evitare accessi concorrenti alla stringa da parte
+del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41})
+il semforo dovrà essere rilasciato (\texttt{\small 42--45}). Il passo finale
+(\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il
+ciclo. 
+
+Per uscire in maniera corretta dal programma sarà necessario interromperlo con
+il break da tastiera (\texttt{C-c}), che corrisponde all'invio del segnale
+\const{SIGINT}, per il quale si è installato (\texttt{\small 10}) una
+opportuna funzione di gestione, riportata in
+fig.~\ref{fig:ipc_posix_sem_shm_message_server_handler}. La funzione è molto
+semplice e richiame le funzioni di rimozione sia per il segmento di memoria
+condivisa che per il semaforo, garantendo così che possa essere riaperto
+ex-novo senza errori in un futuro riutilizzo del comando.
+
+\begin{figure}[!h]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/message_setter.c}
+  \end{minipage} 
+  \normalsize 
+  \caption{Sezione principale del codice del programma
+    \file{message\_setter.c}.}
+  \label{fig:ipc_posix_sem_shm_message_setter}
+\end{figure}
+
+Il secondo programma di esempio è \file{message\_setter.c}, di cui si è
+riportato il corpo principale in
+fig.~\ref{fig:ipc_posix_sem_shm_message_setter},\footnote{al solito il codice
+  completo è nel file dei sorgenti allegati.} dove si è tralasciata, non
+essendo significativa per quanto si sta trattando, la parte relativa alla
+gestione delle opzioni a riga di comando e degli argomenti, che sono identici
+a quelli usati da \file{message\_getter}, con l'unica aggiunta di un'opzione
+``\texttt{-t}'' che consente di indicare un tempo di attesa (in secondi) in
+cui il programma si ferma tenendo bloccato il semaforo.
+
+Una volta completata la gestione delle opzioni e degli argomenti (ne deve
+essere presente uno solo, contenente la nuova stringa da usare come
+messaggio), il programma procede (\texttt{\small 10--14}) con l'acquisizione
+del segmento di memoria condivisa usando la funzione \func{FindShm} (trattata
+in sez.~\ref{sec:ipc_posix_shm}) che stavolta deve già esistere.  Il passo
+successivo (\texttt{\small 16--19}) è quello di aprire il semaforo, e a
+differenza di \file{message\_getter}, in questo caso si richiede a
+\func{sem\_open} che questo esista, passando uno zero come secondo ed unico
+argomento.
+
+Una volta completate con successo le precedenti inizializzazioni, il passo
+seguente (\texttt{\small 21--24}) è quello di acquisire il semaforo, dopo di
+che sarà possibile eseguire la sostituzione del messaggio (\texttt{\small 25})
+senza incorrere in possibili \itindex{race~condition} \textit{race condition}
+con la stampa dello stesso da parte di \file{message\_getter}.
+
+Una volta effettuata la modifica viene stampato (\texttt{\small 26}) il tempo
+di attesa impostato con l'opzione ``\texttt{-t}'' dopo di che (\texttt{\small
+  27}) viene eseguita la stessa, senza rilasciare il semaforo che resterà
+quindi bloccato (causando a questo punto una interruzione delle stampe
+eseguite da \file{message\_getter}). Terminato il tempo di attesa si rilascerà
+(\texttt{\small 29--32}) il semaforo per poi uscire.
+
+Per verificare il funzionamento dei programmi occorrerà lanciare per primo
+\file{message\_getter}\footnote{lanciando per primo \file{message\_setter}
+  darà luogo ad un errore, non essendo stati creati il semaforo ed il segmento
+  di memoria condivisa.} che inizierà a stampare una volta al secondo il
+contenuto del messaggio ed i suoi dati, con qualcosa del tipo:
+\begin{Verbatim}
+piccardi@hain:~/gapil/sources$  ./message_getter messaggio
+sem=1, Fri Dec 31 14:12:41 2010
+message: messaggio
+sem=1, Fri Dec 31 14:12:42 2010
+message: messaggio
+...
+\end{Verbatim}
+%$
+proseguendo indefinitamente fintanto che non si prema \texttt{C-c} per farlo
+uscire. Si noti come il valore del semaforo risulti sempre pari ad 1 (in
+quanto al momento esso sarà sempre libero). 
+
+A questo punto si potrà lanciare \file{message\_setter} per cambiare il
+messaggio, nel nostro caso per rendere evidente il funzionamento del blocco
+richiederemo anche una attesa di 3 secondi, ed otterremo qualcosa del tipo:
+\begin{Verbatim}
+piccardi@hain:~/gapil/sources$ ./message_setter -t 3 ciao
+Sleeping for 3 seconds
+\end{Verbatim}
+%$
+dove il programma si fermerà per 3 secondi prima di rilasciare il semaforo e
+terminare. 
+
+L'effetto di questo programma si potrà però apprezzare meglio nell'uscita di
+\file{message\_getter}, che verrà interrotta per questo stesso tempo, prima di
+ricominciare con il nuovo testo:
+\begin{Verbatim}
+...
+sem=1, Fri Dec 31 14:16:27 2010
+message: messaggio
+sem=1, Fri Dec 31 14:16:28 2010
+message: messaggio
+sem=0, Fri Dec 31 14:16:29 2010
+message: ciao
+sem=1, Fri Dec 31 14:16:32 2010
+message: ciao
+sem=1, Fri Dec 31 14:16:33 2010
+message: ciao
+...
+\end{Verbatim}
+%$
 
+E si noterà come nel momento in cui si è lanciato \file{message\_setter} le
+stampe di \file{message\_getter} si bloccheranno, come corretto, dopo aver
+registrato un valore nullo per il semaforo.  Il programma infatti resterà
+bloccato nella \func{sem\_wait} (quella di riga (\texttt{\small 37}) in
+fig.~\ref{fig:ipc_posix_sem_shm_message_server}) fino alla scadenza
+dell'attesa di \file{message\_setter} (con l'esecuzione della \func{sem\_post}
+della riga (\texttt{\small 29}) di
+fig.~\ref{fig:ipc_posix_sem_shm_message_setter}), e riprenderanno con il nuovo
+testo alla terminazione di quest'ultimo.
 
 
 % LocalWords:  like fifo System POSIX RPC Calls Common Object Request Brocker
@@ -4453,6 +4619,8 @@ di che
 % LocalWords:  CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS
 % LocalWords:  ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait
 % LocalWords:  process getvalue sval execve pshared ENOSYS heap PAGE destroy
+% LocalWords:  xffffffff Arrays owner perms Queues used bytes messages device
+% LocalWords:  Cannot find such Segments getter Signal MSGMAXSIZE
 
 
 %%% Local Variables: 
diff --git a/listati/HandSigInt.c b/listati/HandSigInt.c
new file mode 100644 (file)
index 0000000..3212934
--- /dev/null
@@ -0,0 +1,6 @@
+void HandSigInt(int sig)
+{
+    if (RemoveShm(shmname) != 0) perror("Cannot remove shared memory");
+    if (sem_unlink(semname)!= 0) perror("Cannot remove semaphore") ;
+    exit(0);
+}
diff --git a/listati/message_getter.c b/listati/message_getter.c
new file mode 100644 (file)
index 0000000..4b19bef
--- /dev/null
@@ -0,0 +1,49 @@
+void HandSigInt(int sig);
+#define MSGMAXSIZE 256
+char *shmname = "messages";
+char *semname = "messages";
+
+int main(int argc, char *argv[]) 
+{
+    sem_t * sem, void * shm_ptr, time_t t;
+    ...
+    Signal(SIGINT, HandSigInt);
+    // get a shared memory segment
+    if ((shm_ptr = CreateShm(shmname, MSGMAXSIZE, 0666, 0)) == NULL) {
+       perror("Cannot find shared memory");
+       exit(1);
+    }
+    // get a locked semaphore
+    if ((sem = sem_open(semname, O_CREAT|O_EXCL, 0666, 0)) == SEM_FAILED) {
+       perror("Cannot open semaphore");
+       exit(1);
+    }
+    // set initial string
+    strncpy((char *) shm_ptr, argv[optind], MSGMAXSIZE);
+    // do initial release
+    if (sem_post(sem) != 0) {
+       perror("cannot do semaphore initial release");
+       exit(1);
+    }
+    // main loop
+    while(1) {
+       if (sem_getvalue(sem, &i) !=0) {             // get sem values
+           perror("cannot get semaphore value");
+           exit(1);
+       }
+       printf("sem=%i, ", i);                       // print sem values
+       t = time(NULL);                              // get time
+       printf("%s", ctime(&t));                     // print time
+       if (sem_wait(sem) != 0) {                    // acquire semaphore
+           perror("cannot use semaphore");
+           exit(1);
+       }
+       printf("message: %s\n", (char *) shm_ptr );  // print message
+       if (sem_post(sem) != 0) {                    // release semaphore
+           perror("cannot release semaphore");
+           exit(1);
+       }
+       sleep(1);
+   }
+exit(0);    
+}
diff --git a/listati/message_setter.c b/listati/message_setter.c
new file mode 100644 (file)
index 0000000..1094e39
--- /dev/null
@@ -0,0 +1,34 @@
+#define MSGMAXSIZE 256
+
+int main(int argc, char *argv[]) 
+{
+    int t = 0, sem_t * sem, void *shm_ptr;
+    char *shmname = "messages";
+    char *semname = "messages";
+    ...
+    // get shared memory segment
+    shm_ptr = FindShm(shmname, MSGMAXSIZE);
+    if ( shm_ptr == NULL) {
+       perror("Cannot find shared memory");
+       exit(1);
+    }
+    // open semaphore
+    if ( (sem = sem_open(semname, 0)) == SEM_FAILED ) {
+       perror("Cannot open semaphore");
+       exit(1);
+    }
+    // get semaphore
+    if ( sem_wait(sem) != 0) {
+       perror("cannot use semaphore");
+       exit(1);
+    }
+    strncpy((char *) shm_ptr, argv[optind],  MSGMAXSIZE); // modify message 
+    printf("Sleeping for %i seconds\n", t);               // print wait time
+    sleep(t);                                             // sleep
+    // release semaphore
+    if ( sem_post(sem) != 0) {
+       perror("cannot release semaphore");
+       exit(1);
+    }
+    exit(0);
+}
index 5ffba091b1a1c1a2b4910b026bc0194e70cb9fda..8b3ec2d3c0856bffc35f74b61cfe5a0975303647 100644 (file)
@@ -93,42 +93,38 @@ int main(int argc, char *argv[])
         usage();
     }
     Signal(SIGINT, HandSigInt);
-    // Get shared memory segment
-    shm_ptr = CreateShm(shmname, MSGMAXSIZE, 0666, 0);
-    if ( shm_ptr == NULL) {
+    // get a shared memory segment
+    if ((shm_ptr = CreateShm(shmname, MSGMAXSIZE, 0666, 0)) == NULL) {
        perror("Cannot find shared memory");
        exit(1);
     }
-    // set initial string
-    strncpy((char *) shm_ptr, argv[optind], MSGMAXSIZE);
-    // open the semaphore or create it locked
-    if ( (sem = sem_open(semname, O_CREAT, 0666, 0)) == SEM_FAILED ) {
+    // get a locked semaphore
+    if ((sem = sem_open(semname, O_CREAT|O_EXCL, 0666, 0)) == SEM_FAILED) {
        perror("Cannot open semaphore");
        exit(1);
     }
-    // check if first time creation, and unlock
-    if ( sem_getvalue(sem, &i) != 0) {
-       perror("cannot get initial semaphore value");
+    // set initial string
+    strncpy((char *) shm_ptr, argv[optind], MSGMAXSIZE);
+    // do initial release
+    if (sem_post(sem) != 0) {
+       perror("cannot do semaphore initial release");
        exit(1);
-    } else 
-       if (i == 0)
-           if ( sem_post(sem) != 0) {
-               perror("cannot do semaphore initial release");
-               exit(1);
-           }
+    }
     // main loop
     while(1) {
-       // acquire semaphore
-       if ( sem_wait(sem) != 0) {
+       if (sem_getvalue(sem, &i) !=0) {             // get sem values
+           perror("cannot get semaphore value");
+           exit(1);
+       }
+       printf("sem=%i, ", i);                       // print sem values
+       t = time(NULL);                              // get time
+       printf("%s", ctime(&t));                     // print time
+       if (sem_wait(sem) != 0) {                    // acquire semaphore
            perror("cannot use semaphore");
            exit(1);
        }
-       t = time(NULL);
-       printf("%s", ctime(&t));
-       sem_getvalue(sem, &i);
-       printf("sem=%i,  ", i);
-       printf("message: %s\n", (char *) shm_ptr );
-       if ( sem_post(sem) != 0) {
+       printf("message: %s\n", (char *) shm_ptr );  // print message
+       if (sem_post(sem) != 0) {                    // release semaphore
            perror("cannot release semaphore");
            exit(1);
        }
@@ -152,7 +148,7 @@ void usage(void) {
 
 void HandSigInt(int sig)
 {
-    RemoveShm(shmname);
-    sem_unlink(semname);
+    if (RemoveShm(shmname) != 0) perror("Cannot remove shared memory");
+    if (sem_unlink(semname)!= 0) perror("Cannot remove semaphore") ;
     exit(0);
 }
index f6a8408703fd43e7f0cd647cc2ad1a2850c0db87..823f9f8be6a05becb143cfe8b1843b4cf2220631 100644 (file)
@@ -92,7 +92,7 @@ int main(int argc, char *argv[])
        printf("Wrong number of arguments %d\n", argc - optind);
         usage();
     }
-    // Get shared memory segment
+    // get shared memory segment
     shm_ptr = FindShm(shmname, MSGMAXSIZE);
     if ( shm_ptr == NULL) {
        perror("Cannot find shared memory");
@@ -103,13 +103,15 @@ int main(int argc, char *argv[])
        perror("Cannot open semaphore");
        exit(1);
     }
+    // get semaphore
     if ( sem_wait(sem) != 0) {
        perror("cannot use semaphore");
        exit(1);
     }
-    strncpy((char *) shm_ptr, argv[optind],  MSGMAXSIZE);
-    printf("Sleeping for %i seconds\n", t); 
-    sleep(t);
+    strncpy((char *) shm_ptr, argv[optind],  MSGMAXSIZE); // modify message
+    printf("Sleeping for %i seconds\n", t);               // print sleep value
+    sleep(t);                                             // sleep
+    // release semaphore
     if ( sem_post(sem) != 0) {
        perror("cannot release semaphore");
        exit(1);