Completata la descrizione dell'esempio dei mutex realizzati con i semafori.
authorSimone Piccardi <piccardi@gnulinux.it>
Wed, 20 Nov 2002 23:34:02 +0000 (23:34 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Wed, 20 Nov 2002 23:34:02 +0000 (23:34 +0000)
biblio.bib
ipc.tex
sources/wrappers.h

index f30a1c250c05c4fb9d18f88a86919b147fb7e5cf..a258933bc3f1652842ee7243b1d334f4e2e431c2 100644 (file)
   OPTnote =     {},
   OPTannote =   {}
 }
   OPTnote =     {},
   OPTannote =   {}
 }
+@Book{PratC,
+  author =      {S. Oullaine},
+  editor =      {O'Reilly},
+  title =       {Pratical C},
+  publisher =   {O'Reilly},
+  year =        {2002},
+  OPTkey =      {},
+  OPTvolume =   {},
+  OPTnumber =   {},
+  OPTseries =   {},
+  OPTaddress =          {},
+  OPTedition =          {2nd},
+  OPTmonth =    {},
+  OPTnote =     {},
+  OPTannote =   {}
+}
 @Book{glibc,
   author =      {Sandra Loosemore Richard M. Stallman Roland McGrath Andrew Oram and Ulrich Drepper},
   editor =      {Free Software Foundation},
 @Book{glibc,
   author =      {Sandra Loosemore Richard M. Stallman Roland McGrath Andrew Oram and Ulrich Drepper},
   editor =      {Free Software Foundation},
diff --git a/ipc.tex b/ipc.tex
index 1060b49d15190a352d62cf3ed23acce734c7e64a..9dec79a907d64106343fb941ceac99990aed297b 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -2440,66 +2440,72 @@ ignorare silenziosamente le altre; questo per
 ripristino non è comunque garantito in tutte le occasioni.
 
 Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
 ripristino non è comunque garantito in tutte le occasioni.
 
 Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
-con essa dei semplici \textit{mutex} (cioè semafori binari), tutte le funzioni
-relative sono definite come \ctyp{inline}\footnote{la direttiva \func{inline}
-  viene usata per dire al compilatore di non trattare la funzione cui essa fa
-  riferimento come una funzione, ma di inserire il codice direttamente nel
-  testo del programma. Anche se i compilatori più moderni sono in grado di
-  effettuare da soli queste manipolazioni (impostando le opportune
-  ottimizzazioni) questa è una tecnica usata per migliorare le prestazioni per
-  le funzioni piccole ed usate di frequente, in tal caso infatti le istruzioni
-  per creare un nuovo frame nello stack per chiamare la funzione
-  costituirebbero una parte rilevante del codice, appesantendo inutilmente il
-  programma. Originariamente questa era fatto utilizzando delle macro, ma
-  queste hanno tutta una serie di problemi di sintassi nel passaggio degli
-  argomenti (si veda ad esempio \cite[oullaine]) che in questo modo possono
-  essere evitati.} nel file \file{wrappers.h}. In
-\secref{fig:ipc_mutex_create} si è riportata la definizione delle due funzioni
-che permettono di acquisire il \textit{mutex}; la prima è \func{MutexCreate}
-che crea il semaforo usato per il mutex e lo inizializza, restituendone
-l'identificatore; la seconda è \func{MutexFind}, che data una chiave
-restitituisce l'identificatore del semaforo ad essa associato.
+con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
+in questione, contenuto nel file \file{wrappers.h} allegato ai sorgenti, è
+riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+creare un insieme contenente un singolo semaforo, per il quale poi useremo un
+valore unitario per segnalare la disponibilità della risorsa, ed un valore
+nullo per segnalarne l'indisponibilità. 
 
 \begin{figure}[!bht]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
 
 \begin{figure}[!bht]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}{}
+    \begin{lstlisting}{} 
 /*
 /*
- * Function MutexCreate:
- *
- * Input: an IPC key value (to create an unique semaphore)
- * Return: the semaphore id#
+ * Function MutexCreate: create a mutex/semaphore
  */
  */
-const union semun semunion={1};    /* semaphore union structure */
 inline int MutexCreate(key_t ipc_key) 
 {
 inline int MutexCreate(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,IPC_CREAT|0666))<0 ){ /* get sem ID */
-        perror("cannot create semaphore");     /* a sem_id <0 is an error */
-        printf("semid=%d",sem_id);
-        exit(1);
+    const union semun semunion={1};             /* semaphore union structure */
+    int sem_id, ret;
+    sem_id = semget(ipc_key, 1, IPC_CREAT|0666);         /* get semaphore ID */
+    if (sem_id == -1) {                              /* if error return code */
+        return sem_id;
     }
     }
-    if ( (semctl(sem_id,0,SETVAL,semunion)) < 0 ) {
-        perror("cannot init semaphore");       /* <0 is an error */
-        printf("on semid=%d",sem_id);
-        exit(1);
+    ret = semctl(sem_id, 0, SETVAL, semunion);             /* init semaphore */
+    if (ret == -1) {
+        return ret;
     }
     return sem_id;
 }
 /*
     }
     return sem_id;
 }
 /*
- * Find Mutex
- * get the semaphore/mutex Id given the IPC key value
- *
- * Input: an IPC key value
+ * Function MutexFind: get the semaphore/mutex Id given the IPC key value
  */
 inline int MutexFind(key_t ipc_key) 
 {
  */
 inline int MutexFind(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,0))<0 ){       /* find sem .ID */
-        perror("cannot find semaphore");
-        exit(1);
-    }
-    return sem_id;
+    return semget(ipc_key,1,0);
+}
+/*
+ * Function MutexRead: read the current value of the mutex/semaphore
+ */
+inline int MutexRead(int sem_id) 
+{
+    return semctl(sem_id, 0, GETVAL);
+}
+/*
+ * Define sembuf structures to lock and unlock the semaphore 
+ */
+struct sembuf sem_lock={                                /* to lock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    -1,                                    /* operation (-1 to use resource) */
+    SEM_UNDO};                                /* flag (set for undo at exit) */
+struct sembuf sem_ulock={                             /* to unlock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    1,                                  /* operation (1 to release resource) */
+    SEM_UNO};                                       /* flag (in this case 0) */
+/*
+ * Function MutexLock: to lock a mutex/semaphore
+ */
+inline int MutexLock(int sem_id) 
+{
+    return semop(sem_id, &sem_lock, 1);
+}
+/*
+ * Function MutexUnlock: to unlock a mutex/semaphore
+ */
+inline int MutexUnlock(int sem_id) 
+{
+    return semop(sem_id, &sem_ulock, 1);
 }
     \end{lstlisting}
   \end{minipage} 
 }
     \end{lstlisting}
   \end{minipage} 
@@ -2509,16 +2515,72 @@ inline int MutexFind(key_t ipc_key)
   \label{fig:ipc_mutex_create}
 \end{figure}
 
   \label{fig:ipc_mutex_create}
 \end{figure}
 
-
-La prima funzione definita (\texttt{\small 8--22}) è \func{MutexCreate},
-anzitutto (\texttt{\small 11--15}) si chiama \func{semget} con
-\macro{IPC\_CREATE} per creare il semaforo qualora non esista, assegnandogli i
-privilegi di lettura e scrittura per l'utente. In caso di errore si
-scrive un errore e si esce. 
-
-
-
-
+La prima funzione (\texttt{\small 1--17}) è \func{MutexCreate} che data una
+chiave crea il semaforo usato per il mutex e lo inizializza, restituendone
+l'identificatore. Il primo passo (\texttt{\small 8}) è chiamare \func{semget}
+con \macro{IPC\_CREATE} per creare il semaforo qualora non esista,
+assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore
+(\texttt{\small 9--11}) si ritorna subito il risultato di \func{semget},
+altrimenti (\texttt{\small 12}) si inizializza il semaforo chiamando
+\func{semctl} con il comando \macro{SETVAL}, utilizzando l'unione
+\var{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 6}) ad 1
+per significare che risorsa è libera. In caso di errore (\texttt{\small
+  13--16}) si restituisce il valore di ritorno di \func{semctl}, altrimenti si
+ritorna l'identificatore del semaforo.
+
+La seconda funzione (\texttt{\small 18--24}) è \func{MutexFind}, che data una
+chiave, restituisce l'identificatore del semaforo ad essa associato. La
+comprensione del suo funzionamento è immediata in quanto è solo un
+\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
+  \textsl{involucro} alla chiamata di un altra, usata in genere per
+  semplificare un'interfaccia (come in questo caso) o per utilizzare con la
+  stessa funzione diversi substrati (librerie, ecc.)  che possono fornire le
+  stesse funzionalità.} di \func{semget} per cercare l'identificatore
+associato alla chiave, restituendo direttamente il valore di ritorno della
+funzione.
+
+La terza funzione (\texttt{\small 25--31}) è \func{MutexRead} che, dato
+l'identificatore, restituisce il valore del mutex. Anche in questo caso la
+funzione è un \textit{wrapper} per la chiamata di \func{semctl}, questa volta
+con il comando \macro{GETVAL}, che permette di restituire il valore del
+semaforo.
+
+La quarta e la quinta funzione (\texttt{\small 43--56}) sono \func{MutexLock},
+e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare
+il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due
+strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza
+(\texttt{\small 32--42}). Si noti come per queste ultime si sia fatto uso
+dell'opzione \macro{SEM\_UNDO} per evitare che il semaforo resti bloccato in
+caso di terminazione imprevista del processo. Si noti infine come, essendo
+tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente
+semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva
+  \func{inline} viene usata per dire al compilatore di non trattare la
+  funzione cui essa fa riferimento come una funzione, ma di inserire il codice
+  direttamente nel testo del programma.  Anche se i compilatori più moderni
+  sono in grado di effettuare da soli queste manipolazioni (impostando le
+  opportune ottimizzazioni) questa è una tecnica usata per migliorare le
+  prestazioni per le funzioni piccole ed usate di frequente, in tal caso
+  infatti le istruzioni per creare un nuovo frame nello stack per chiamare la
+  funzione costituirebbero una parte rilevante del codice, appesantendo
+  inutilmente il programma. Originariamente questa era fatto utilizzando delle
+  macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio
+  degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono
+  essere evitati.}
+
+
+Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
+libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
+chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
+rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
+incrementato di uno, sbloccandolo qualora fosse bloccato.  Si noti che occorre
+eseguire sempre prima \func{MutexLock} e poi \func{MutexUnlock}, perché se per
+un qualche errore si esegue più volte quest'ultima il valore del semaforo
+crescerebbe oltre 1, e \func{MutexLock} non avrebbe più l'effetto aspettato
+(bloccare la risorsa quando questa è considerata libera). Si tenga presente
+che usare \func{MutexRead} per controllare il valore dei mutex prima di
+proseguire non servirebbe comunque, dato che l'operazione non sarebbe atomica.
+Vedremo in \secref{sec:ipc_posix_sem} come è possibile ottenere un'interfaccia
+analoga senza questo problemi usando il file locking.
 
 
 
 
 
 
@@ -2578,7 +2640,7 @@ lettura si deve essere sicuri che i dati restano coerenti e non vengono
 sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
 altro processo; per questo in genere la memoria condivisa viene sempre
 utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
 sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
 altro processo; per questo in genere la memoria condivisa viene sempre
 utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
-norma, significa insime a dei semafori.
+norma, significa insieme a dei semafori.
 
 \begin{figure}[!htb]
   \footnotesize \centering
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -2615,7 +2677,7 @@ invece:
   inizializzato al valore di \param{size}.
 \item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
   segmento, viene inizializzato al tempo corrente.
   inizializzato al valore di \param{size}.
 \item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
   segmento, viene inizializzato al tempo corrente.
-\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimno
+\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimono
   rispettivamente il tempo dell'ultima volta che il segmento è stato
   agganciato o sganciato da un processo, vengono inizializzati a zero.
 \item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
   rispettivamente il tempo dell'ultima volta che il segmento è stato
   agganciato o sganciato da un processo, vengono inizializzati a zero.
 \item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
@@ -2795,7 +2857,7 @@ In caso di successo la funzione aggiorna anche i seguenti campi di
 \end{itemize*} 
 
 Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
 \end{itemize*} 
 
 Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
-agganciato ad un precesso viene ereditato da un figlio attraverso una
+agganciato ad un processo viene ereditato da un figlio attraverso una
 \func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
 indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
 eseguito un diverso programma con uno spazio di indirizzi completamente
 \func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
 indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
 eseguito un diverso programma con uno spazio di indirizzi completamente
@@ -2920,12 +2982,12 @@ polling\index{polling}, che 
 
 Per questo motivo la tecnica alternativa più pulita è quella di fare ricorso
 al \textit{file locking} visto in \secref{sec:file_locking} ed utilizzare
 
 Per questo motivo la tecnica alternativa più pulita è quella di fare ricorso
 al \textit{file locking} visto in \secref{sec:file_locking} ed utilizzare
-\func{fcntl} su un file creato per l'occazione per ottenere un write lock; in
+\func{fcntl} su un file creato per l'occasione per ottenere un write lock; in
 questo modo potremo usare il lock come un \textit{mutex}: per bloccare la
 risorsa basterà acquisire il lock, per sbloccarla basterà rilasciare il lock;
 una richiesta fatta con un write lock metterà automaticamente il processo in
 stato di attesa, senza necessità di ricorrere al
 questo modo potremo usare il lock come un \textit{mutex}: per bloccare la
 risorsa basterà acquisire il lock, per sbloccarla basterà rilasciare il lock;
 una richiesta fatta con un write lock metterà automaticamente il processo in
 stato di attesa, senza necessità di ricorrere al
-\textit{polling}\index{polling} per determimanare la dispobilità della
+\textit{polling}\index{polling} per determinare la disponibilità della
 risorsa, e al rilascio della stessa da parte del processo che la occupava si
 otterrà il nuovo lock atomicamente.
 
 risorsa, e al rilascio della stessa da parte del processo che la occupava si
 otterrà il nuovo lock atomicamente.
 
index ee8fa89da88d4d85489ae1bb209807408907eeab..15ddd826c2f3500668632b8d1cea932e6a95fef1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Author: S. Piccardi
  *
  *
  * Author: S. Piccardi
  *
- * $Id: wrappers.h,v 1.3 2002/08/18 23:24:44 piccardi Exp $
+ * $Id: wrappers.h,v 1.4 2002/11/20 23:34:02 piccardi Exp $
  *
  ***************************************************************/
 #include <sys/sem.h>     /* IPC semaphore declarations */
  *
  ***************************************************************/
 #include <sys/sem.h>     /* IPC semaphore declarations */
@@ -32,45 +32,8 @@ union semun {
 };
 #endif
 /*
 };
 #endif
 /*
- * Define the sem_lock and sem_ulock sembuf structures to 
- * lock and unlock the semaphore (used to implement a mutex)
- */
-struct sembuf sem_lock={      /* to lock semaphore */
-    0,    /* semaphore number (only one so 0) */
-    -1,   /* semaphore operation (-1 to use resource) */
-    0};   /* semaphore flag (in this case 0) */
-struct sembuf sem_ulock={     /* to unlock semaphore */
-    0,    /* semaphore number (only one so 0) */
-    1,    /* semaphore operation (-1 to release resource) */
-    0};   /* semaphore flag (in this case 0) */
-/*
- * Function MutexLock:
- * to lock a mutex/semaphore
- *
- * Input: a semaphore id #
- */
-inline void MutexLock(int sem_id) 
-{
-    if (semop(sem_id,&sem_lock,1)) {
-       perror("Cannot lock the semaphore");
-       exit(1);
-    }
-}
-/*
- * Function MutexUnlock
- * to unlock a mutex/semaphore
+ * Function MutexCreate: create a mutex/semaphore
  *
  *
- * Input: a semaphore id #
- */
-inline void MutexUnlock(int sem_id) 
-{
-    if (semop(sem_id,&sem_ulock,1)) {
-       perror("Cannot unlock the semaphore");
-       exit(1);
-    }
-}
-/*
- * Function MutexCreate:
  * First call create a semaphore, using the given key. 
  * We want only one semaphore so we set second argument to 1; third 
  * parameter is the flag argument, and is set to create a semaphore 
  * First call create a semaphore, using the given key. 
  * We want only one semaphore so we set second argument to 1; third 
  * parameter is the flag argument, and is set to create a semaphore 
@@ -78,55 +41,72 @@ inline void MutexUnlock(int sem_id)
  * Second call initialize the semaphore to 1 (unlocked)
  *
  * Input: an IPC key value (to create an unique semaphore)
  * Second call initialize the semaphore to 1 (unlocked)
  *
  * Input: an IPC key value (to create an unique semaphore)
- * Return: the semaphore id#
+ * Return: the semaphore id# or -1 on error
  */
  */
-const union semun semunion={1};    /* semaphore union structure */
 inline int MutexCreate(key_t ipc_key) 
 {
 inline int MutexCreate(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,IPC_CREAT|0666))<0 ){ /* get sem ID */
-       perror("cannot create semaphore");     /* a sem_id <0 is an error */
-       printf("semid=%d",sem_id);
-       exit(1);
+    const union semun semunion={1};             /* semaphore union structure */
+    int sem_id, ret;
+    sem_id = semget(ipc_key, 1, IPC_CREAT|0666);         /* get semaphore ID */
+    if (sem_id == -1) {                              /* if error return code */
+       return sem_id;
     }
     }
-    if ( (semctl(sem_id,0,SETVAL,semunion)) < 0 ) {
-        perror("cannot init semaphore");       /* <0 is an error */
-       printf("on semid=%d",sem_id);
-       exit(1);
+    ret = semctl(sem_id, 0, SETVAL, semunion);             /* init semaphore */
+    if (ret == -1) {
+       return ret;
     }
     return sem_id;
 }
 /*
     }
     return sem_id;
 }
 /*
- * Find Mutex
- * get the semaphore/mutex Id given the IPC key value
+ * Function MutexFind: get the semaphore/mutex Id given the IPC key value
  *
  * Input: an IPC key value
  */
 inline int MutexFind(key_t ipc_key) 
 {
  *
  * Input: an IPC key value
  */
 inline int MutexFind(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,0))<0 ){       /* find sem .ID */
-       perror("cannot find semaphore");
-        exit(1);
-    }
-    return sem_id;
+    return semget(ipc_key,1,0);
 }
 /*
 }
 /*
- * Function MutexRead:
- * Read the current value of the mutex/semaphore
+ * Function MutexRead: read the current value of the mutex/semaphore
  *
  * Input:  a semaphore id #
  * Return: the semaphore value
  */
 inline int MutexRead(int sem_id) 
 {
  *
  * Input:  a semaphore id #
  * Return: the semaphore value
  */
 inline int MutexRead(int sem_id) 
 {
-    int value;
-    if ( (value=semctl(sem_id,0,GETVAL,semunion)) < 0 ) {
-             perror("cannot read semaphore");       /* a <0 is an error */
-             printf("on semid=%d\n",sem_id);
-             exit(1);
-    } 
-    return value;
+    return semctl(sem_id, 0, GETVAL);
+}
+/*
+ * Define sembuf structures to lock and unlock the semaphore 
+ * (used to implement a mutex)
+ */
+struct sembuf sem_lock={                                /* to lock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    -1,                                    /* operation (-1 to use resource) */
+    SEM_UNDO};                                /* flag (set for undo at exit) */
+struct sembuf sem_ulock={                             /* to unlock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    1,                                  /* operation (1 to release resource) */
+    SEM_UNO};                                       /* flag (in this case 0) */
+/*
+ * Function MutexLock: to lock a mutex/semaphore
+ *
+ * Input:  a semaphore id #
+ * Output: semop return code  (0 OK, -1 KO)
+ */
+inline int MutexLock(int sem_id) 
+{
+    return semop(sem_id, &sem_lock, 1);
+}
+/*
+ * Function MutexUnlock: to unlock a mutex/semaphore
+ *
+ * Input:  a semaphore id #
+ * Return: semop return code (0 OK, -1 KO)
+ */
+inline int MutexUnlock(int sem_id) 
+{
+    return semop(sem_id, &sem_ulock, 1);
 }
 /*
  * Function ShmCreate:
 }
 /*
  * Function ShmCreate: