\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-/*
- * Function MutexCreate: create a mutex/semaphore
- */
+/* Function MutexCreate: create a mutex/semaphore */
int MutexCreate(key_t ipc_key)
{
const union semun semunion={1}; /* semaphore union structure */
}
return sem_id;
}
-/*
- * Function MutexFind: get the semaphore/mutex Id given the IPC key value
- */
+/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */
int MutexFind(key_t ipc_key)
{
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 */
int MutexRead(int sem_id)
{
return semctl(sem_id, 0, GETVAL);
}
-/*
- * Define sembuf structures to lock and unlock the semaphore
- */
+/* 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) */
0, /* semaphore number (only one so 0) */
1, /* operation (1 to release resource) */
SEM_UNDO}; /* flag (in this case 0) */
-/*
- * Function MutexLock: to lock a mutex/semaphore
- */
+/* Function MutexLock: to lock a mutex/semaphore */
int MutexLock(int sem_id)
{
return semop(sem_id, &sem_lock, 1);
}
-/*
- * Function MutexUnlock: to unlock a mutex/semaphore
- */
+/* Function MutexUnlock: to unlock a mutex/semaphore */
int MutexUnlock(int sem_id)
{
return semop(sem_id, &sem_ulock, 1);
+}
+/* Function MutexRemove: remove a mutex/semaphore */
+int MutexRemove(int sem_id)
+{
+ return semctl(sem_id, 0, IPC_RMID);
}
\end{lstlisting}
\end{minipage}
\label{fig:ipc_mutex_create}
\end{figure}
-La prima funzione (\texttt{\small 1--17}) è \func{MutexCreate} che data una
+La prima funzione (\texttt{\small 2--15}) è \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}
+l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget}
con \const{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
+(\texttt{\small 7--9}) si ritorna subito il risultato di \func{semget},
+altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando
\func{semctl} con il comando \const{SETVAL}, utilizzando l'unione
-\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 6})
+\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4})
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.
+ 11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
+(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
-La seconda funzione (\texttt{\small 18--24}) è \func{MutexFind}, che data una
+La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una
chiave, restituisce l'identificatore del semaforo ad essa associato. La
-comprensione del suo funzionamento è immediata in quanto è solo un
+comprensione del suo funzionamento è immediata in quanto essa è soltanto 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.
+ stesse funzionalità.} di una chiamata a \func{semget} per cercare
+l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
+viene passato all'indietro al chiamante.
-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 \const{GETVAL}, che permette di restituire il valore del
-semaforo.
+La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un
+identificatore, restituisce il valore del semaforo associato al mutex. Anche
+in questo caso la funzione è un \textit{wrapper} per una chiamata a
+\func{semctl} con il comando \const{GETVAL}, che permette di restituire il
+valore del semaforo.
-La quarta e la quinta funzione (\texttt{\small 43--56}) sono \func{MutexLock},
+La quarta e la quinta funzione (\texttt{\small 36--44}) 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
+(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso
dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
caso di terminazione imprevista del processo.
+L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove},
+che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a
+\func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il
+smemaforo; il valore di ritorno di quest'ultima viene passato all'indietro.
+
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
(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\index{file!locking}.
+Vedremo in \secref{sec:ipc_lock_file} come sia possibile ottenere
+un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
+problemi, usando il file locking\index{file!locking}.
sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è
relativamente poco diffuso.
-
-
\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}
Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi
problemi, che non lo rendono una alternativa praticabile per la
-sincronizzazione: anzitutto anche in questo caso, in caso di terminazione
-imprevista del processo, si lascia allocata la risorsa (il \textsl{file di
- lock}) e questa deve essere sempre cancellata esplicitamente. Inoltre il
-controllo della disponibilità può essere eseguito solo con una tecnica di
-\textit{polling}\index{polling}, ed è quindi molto inefficiente.
+sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
+si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
+sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
+può essere eseguito solo con una tecnica di \textit{polling}\index{polling},
+ed è quindi molto inefficiente.
-La tecnica dei file di lock non di meno ha una sua utilità, e può essere usata
+La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
usa spesso per evitare interferenze sull'uso delle porte seriali da parte di
\subsection{La sincronizzazione con il \textit{file locking}}
\label{sec:ipc_lock_file}
-Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
-la tecnica alternativa più comune è quella di fare ricorso al \textit{file
- locking}\index{file!locking} (trattato in \secref{sec:file_locking}) usando
-\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
-\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.
+Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
+illustrati in precedenza, la tecnica alternativa di sincronizzazione più
+comune è quella di fare ricorso al \textit{file locking}\index{file!locking}
+(trattato in \secref{sec:file_locking}) usando \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 \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.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
-chiusura dei relativi file) e non ci si deve preoccupare di niente, inoltre
-non consuma risorse permanentemente allocate nel sistema, lo svantaggio è che
-dovendo fare ricorso a delle operazioni sul filesystem esso è in genere
+chiusura dei relativi file) e non ci si deve preoccupare di niente; inoltre
+non consuma risorse permanentemente allocate nel sistema. Lo svantaggio è che,
+dovendo fare ricorso a delle operazioni sul filesystem, esso è in genere
leggermente più lento.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-/*
- * Function LockMutex: lock a file (creating it if not existent).
- */
-int LockMutex(const char *path_name)
+/* Function CreateMutex: Create a mutex using file locking. */
+int CreateMutex(const char *path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/* Function UnlockMutex: unlock a file. */
+int FindMutex(const char *path_name)
+{
+ return open(path_name, O_RDWR);
+}
+/* Function LockMutex: lock mutex using file locking. */
+int LockMutex(int fd)
{
- int fd, res;
struct flock lock; /* file lock structure */
/* first open the file (creating it if not existent) */
- if ( (fd = open(path_name, O_EXCL|O_CREAT)) < 0) { /* first open file */
- return fd;
- }
/* set flock structure */
lock.l_type = F_WRLCK; /* set type: read or write */
lock.l_whence = SEEK_SET; /* start from the beginning of the file */
lock.l_start = 0; /* set the start of the locked region */
lock.l_len = 0; /* set the length of the locked region */
/* do locking */
- if ( (res = fcntl(fd, F_SETLKW, &lock)) < 0 ) {
- return res;
- }
- return 0;
+ return fcntl(fd, F_SETLKW, &lock);
}
-/*
- * Function UnlockMutex: unlock a file.
- */
-int UnlockMutex(const char *path_name)
+/* Function UnlockMutex: unlock a file. */
+int UnlockMutex(int fd)
{
- int fd, res;
struct flock lock; /* file lock structure */
- /* first open the file */
- if ( (fd = open(path_name, O_RDWR)) < 0) { /* first open file */
- return fd;
- }
/* set flock structure */
lock.l_type = F_UNLCK; /* set type: unlock */
lock.l_whence = SEEK_SET; /* start from the beginning of the file */
lock.l_start = 0; /* set the start of the locked region */
lock.l_len = 0; /* set the length of the locked region */
/* do locking */
- if ( (res = fcntl(fd, F_SETLK, &lock)) < 0 ) {
+ return fcntl(fd, F_SETLK, &lock);
+}
+/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
+int RemoveMutex(const char *path_name)
+{
+ return unlink(path_name);
+}
+/* Function ReadMutex: read a mutex status. */
+int ReadMutex(int fd)
+{
+ int res;
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
return res;
}
- return 0;
+ return lock.l_type;
}
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{Il codice delle funzioni che permettono di creare un
- \textit{mutex} utilizzando il file locking\index{file!locking}.}
+ \caption{Il codice delle funzioni che permettono per la gestione dei
+ \textit{mutex} con il file locking\index{file!locking}.}
\label{fig:ipc_flock_mutex}
\end{figure}
-Il codice per implementare un mutex utilizzando il file
-locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex}; a
-differenza del precedente caso in cui si sono usati i semafori le funzioni
-questa volta sono sufficienti due funzioni, \func{LockMutex} e
-\func{UnlockMutex}, usate rispettivamente per acquisire e rilasciare il mutex.
-
-La prima funzione (\texttt{\small 1--22}) serve per acquisire il mutex.
-Anzitutto si apre (\texttt{\small 9--11}), creandolo se non esiste, il file
-specificato dall'argomento \param{pathname}. In caso di errore si ritorna
-immediatamente, altrimenti si prosegue impostando (\texttt{\small 12--16}) la
-struttura \var{lock} in modo da poter acquisire un write lock sul file.
-Infine si richiede (\texttt{\small 17--20}) il file lock (restituendo il
-codice di ritorno di \func{fcntl} caso di errore). Se il file è libero il lock
-è acquisito e la funzione ritorna immediatamente; altrimenti \func{fcntl} si
-bloccherà (si noti che la si è chiamata con \func{F\_SETLKW}) fino al rilascio
-del lock.
-
-La seconda funzione (\texttt{\small 23--44}) serve a rilasciare il mutex. Di
-nuovo si apre (\texttt{\small 30--33}) il file specificato dall'argomento
-\param{pathname} (che stavolta deve esistere), ritornando immediatamente in
-caso di errore. Poi si passa ad inizializzare (\texttt{\small 34--38}) la
-struttura \var{lock} per il rilascio del lock, che viene effettuato
-(\texttt{\small 39--42}) subito dopo.
+Il codice delle varie funzioni usate per implementare un mutex utilizzando il
+file locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex};
+si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
+usano i semafori, anche se le due interfacce non possono essere completamente
+equivalenti, specie per quanto riguarda la rimozione del mutex.
+
+La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
+creare il mutex; la funzione è estremamente semplice, si limita
+(\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il
+file che sarà usato per il successivo file locking, assicurandosi che non
+esista già (nel qual caso segnala un errore); poi restituisce il file
+descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
+mutex.
+
+La seconda funzione (\texttt{\small 6--10}) è \func{FindMutex}, che, come la
+precedente, è stata definita per mantenere una analogia con la corrispondente
+funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad
+aprire il file da usare per il file locking, solo che in questo caso le
+opzioni di \func{open} sono tali che il file in questione deve esistere di
+già.
+
+La terza funzione (\texttt{\small 11--23}) è \func{LockMutex} e serve per
+acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
+(\texttt{\small 17--20}) la struttura \var{lock} da usare per acquisire un
+write lock sul file, che poi (\texttt{\small 21}) viene richiesto con
+\func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è
+libero il lock viene acquisito e la funzione ritorna immediatamente;
+altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con
+\func{F\_SETLKW}) fino al rilascio del lock.
+
+La quarta funzione (\texttt{\small 24--35}) è \func{UnlockMutex} e serve a
+rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
+caso si inizializza (\texttt{\small 29--32}) la struttura \var{lock} per il
+rilascio del lock, che viene effettuato (\texttt{\small 34}) con la opportuna
+chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si
+riveda quanto detto \secref{sec:file_posix_lock}) solo il processo che ha
+precedentemente eseguito il lock può sbloccare il mutex.
+
+La quinta funzione (\texttt{\small 36--40}) è \func{RemoveMutex} e serve a
+cancellare il mutex. Anche questa funzione è stata definita per mantenere una
+analogia con le funzioni basate sui semafori, e si limita a cancellare
+(\texttt{\small 39}) il file con una chiamata ad \func{unlink}. Si noti che in
+questo caso la funzione non ha effetto sui mutex già ottenuti con precedenti
+chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere
+disponibili fintanto che i relativi file descriptor restano aperti. Pertanto
+per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure
+chiudere il file usato per il lock.
+
+La sesta funzione (\texttt{\small 41--56}) legge lo stato del mutex.
+
+Basandosi sulla semantica dei file lock POSIX valgono tutte le precisazioni
+relative al comportamento di questi ultimi fatte in
+\secref{sec:file_posix_lock}; questo significa che, al contrario di quanto
+avveniva con l'altra interfaccia basata sui semafori, chiamate multiple a
+\func{UnlockMutex} o \func{LockMutex} non hanno nessun inconveniente.
\subsection{Il \textit{memory mapping} anonimo}