Il kernel mantiene una tabella dei processi attivi, la cosiddetta
\textit{process table}; per ciascun processo viene mantenuta una voce nella
-tabella dei processi costituita da una struttura \type{task\_struct}, che
+tabella dei processi costituita da una struttura \struct{task\_struct}, che
contiene tutte le informazioni rilevanti per quel processo. Tutte le strutture
usate a questo scopo sono dichiarate nell'header file \file{linux/sched.h}, ed
uno schema semplificato, che riporta la struttura delle principali informazioni
-contenute nella \type{task\_struct} (che in seguito incontreremo a più
+contenute nella \struct{task\_struct} (che in seguito incontreremo a più
riprese), è mostrato in \figref{fig:proc_task_struct}.
\begin{figure}[htb]
Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
sono stati creati, questo viene chiamato in genere \acr{ppid} (da
\textit{parent process id}). Questi due identificativi possono essere
-ottenuti da programma usando le funzioni:
+ottenuti usando le due funzioni \funcd{getpid} e \funcd{getppid}, i cui
+prototipi sono:
\begin{functions}
- \headdecl{sys/types.h} \headdecl{unistd.h} \funcdecl{pid\_t getpid(void)}
- Restituisce il \acr{pid} del processo corrente. \funcdecl{pid\_t
- getppid(void)} Restituisce il \acr{pid} del padre del processo corrente.
+ \headdecl{sys/types.h}
+ \headdecl{unistd.h}
+ \funcdecl{pid\_t getpid(void)}
+
+ Restituisce il \acr{pid} del processo corrente.
+
+ \funcdecl{pid\_t getppid(void)}
+
+ Restituisce il \acr{pid} del padre del processo corrente.
\bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
\end{functions}
\subsection{La funzione \func{fork}}
\label{sec:proc_fork}
-La funzione \func{fork} è la funzione fondamentale della gestione dei
+La funzione \funcd{fork} è la funzione fondamentale della gestione dei
processi: come si è detto l'unico modo di creare un nuovo processo è
attraverso l'uso di questa funzione, essa quindi riveste un ruolo centrale
tutte le volte che si devono scrivere programmi che usano il multitasking. Il
\item il \acr{pid} (\textit{process id}).
\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
impostato al \acr{pid} del padre.
-\item i valori dei tempi di esecuzione della struttura \var{tms} (vedi
+\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
\secref{sec:sys_cpu_times}) che nel figlio sono posti a zero.
-\item i \textit{file lock} (vedi \secref{sec:file_locking}), che non
+\item i \textit{lock} sui file (vedi \secref{sec:file_locking}), che non
vengono ereditati dal figlio.
\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che
per il figlio vengono cancellati.
Dato che Linux supporta il \textit{copy on write}\index{copy on write} la
perdita di prestazioni è assolutamente trascurabile, e l'uso di questa
-funzione (che resta un caso speciale della funzione \func{clone}), è
+funzione (che resta un caso speciale della system call \func{\_\_clone}), è
deprecato; per questo eviteremo di trattarla ulteriormente.
571 pts/0 Z 0:00 [forktest <defunct>]
572 pts/0 R 0:00 ps T
\end{verbatim} %$
-\normalsize
-e come si vede, dato che non si è fatto nulla per riceverne lo stato di
-terminazione, i tre processi figli sono ancora presenti pur essendosi
-conclusi, con lo stato di zombie e l'indicazione che sono stati terminati.
-
-La possibilità di avere degli zombie deve essere tenuta sempre presente quando
-si scrive un programma che deve essere mantenuto in esecuzione a lungo e
-creare molti figli. In questo caso si deve sempre avere cura di far leggere
-l'eventuale stato di uscita di tutti i figli (in genere questo si fa
+\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo
+stato di terminazione, i tre processi figli sono ancora presenti pur essendosi
+conclusi, con lo stato di zombie\index{zombie} e l'indicazione che sono stati
+terminati.
+
+La possibilità di avere degli zombie\index{zombie} deve essere tenuta sempre
+presente quando si scrive un programma che deve essere mantenuto in esecuzione
+a lungo e creare molti figli. In questo caso si deve sempre avere cura di far
+leggere l'eventuale stato di uscita di tutti i figli (in genere questo si fa
attraverso un apposito \textit{signal handler}, che chiama la funzione
\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa
-operazione è necessaria perché anche se gli \textit{zombie} non consumano
-risorse di memoria o processore, occupano comunque una voce nella tabella dei
-processi, che a lungo andare potrebbe esaurirsi.
+operazione è necessaria perché anche se gli \textit{zombie}\index{zombie} non
+consumano risorse di memoria o processore, occupano comunque una voce nella
+tabella dei processi, che a lungo andare potrebbe esaurirsi.
Si noti che quando un processo adottato da \cmd{init} termina, esso non
-diviene uno \textit{zombie}; questo perché una delle funzioni di \cmd{init} è
-appunto quella di chiamare la funzione \func{wait} per i processi cui fa da
-padre, completandone la terminazione. Questo è quanto avviene anche quando,
-come nel caso del precedente esempio con \cmd{forktest}, il padre termina con
-dei figli in stato di zombie: alla sua terminazione infatti tutti i suoi figli
-(compresi gli zombie) verranno adottati da \cmd{init}, il quale provvederà a
-completarne la terminazione.
+diviene uno \textit{zombie}\index{zombie}; questo perché una delle funzioni di
+\cmd{init} è appunto quella di chiamare la funzione \func{wait} per i processi
+cui fa da padre, completandone la terminazione. Questo è quanto avviene anche
+quando, come nel caso del precedente esempio con \cmd{forktest}, il padre
+termina con dei figli in stato di zombie\index{zombie}: alla sua terminazione
+infatti tutti i suoi figli (compresi gli zombie\index{zombie}) verranno
+adottati da \cmd{init}, il quale provvederà a completarne la terminazione.
-Si tenga presente infine che siccome gli zombie sono processi già usciti, non
-c'è modo di eliminarli con il comando \cmd{kill}; l'unica possibilità di
-cancellarli dalla tabella dei processi è quella di terminare il processo che
-li ha generati, in modo che \cmd{init} possa adottarli e provvedere a
-concluderne la terminazione.
+Si tenga presente infine che siccome gli zombie\index{zombie} sono processi
+già usciti, non c'è modo di eliminarli con il comando \cmd{kill}; l'unica
+possibilità di cancellarli dalla tabella dei processi è quella di terminare il
+processo che li ha generati, in modo che \cmd{init} possa adottarli e
+provvedere a concluderne la terminazione.
\subsection{Le funzioni \func{wait} e \func{waitpid}}
principale attende le richieste che vengono poi soddisfatte da una serie di
processi figli. Si è già sottolineato al paragrafo precedente come in questo
caso diventi necessario gestire esplicitamente la conclusione dei figli onde
-evitare di riempire di \textit{zombie} la tabella dei processi; le funzioni
-deputate a questo compito sono sostanzialmente due, \func{wait} e
+evitare di riempire di \textit{zombie}\index{zombie} la tabella dei processi;
+le funzioni deputate a questo compito sono sostanzialmente due, \funcd{wait} e
\func{waitpid}. La prima, il cui prototipo è:
\begin{functions}
\headdecl{sys/types.h}
più volte se si vuole recuperare lo stato di terminazione di tutti quanti.
Al ritorno della funzione lo stato di terminazione del figlio viene salvato
-nella variabile puntata da \var{status} e tutte le risorse del kernel relative
-al processo (vedi \secref{sec:proc_termination}) vengono rilasciate. Nel caso
-un processo abbia più figli il valore di ritorno (il \acr{pid} del figlio)
-permette di identificare qual'è quello che è uscito.
+nella variabile puntata da \param{status} e tutte le risorse del kernel
+relative al processo (vedi \secref{sec:proc_termination}) vengono rilasciate.
+Nel caso un processo abbia più figli il valore di ritorno (il \acr{pid} del
+figlio) permette di identificare qual'è quello che è uscito.
Questa funzione ha il difetto di essere poco flessibile, in quanto ritorna
all'uscita di un qualunque processo figlio. Nelle occasioni in cui è
provvedere a ripetere la chiamata alla funzione nel caso il processo cercato
sia ancora attivo.
-Per questo motivo lo standard POSIX.1 ha introdotto la funzione \func{waitpid}
-che effettua lo stesso servizio, ma dispone di una serie di funzionalità più
-ampie, legate anche al controllo di sessione (si veda
+Per questo motivo lo standard POSIX.1 ha introdotto la funzione
+\funcd{waitpid} che effettua lo stesso servizio, ma dispone di una serie di
+funzionalità più ampie, legate anche al controllo di sessione (si veda
\secref{sec:sess_job_control}). Dato che è possibile ottenere lo stesso
comportamento di \func{wait} si consiglia di utilizzare sempre questa
funzione, il cui prototipo è:
\hline
$<-1$& -- & attende per un figlio il cui \textit{process group} (vedi
\secref{sec:sess_proc_group}) è uguale al
- valore assoluto di \var{pid}. \\
+ valore assoluto di \param{pid}. \\
$-1$ & \const{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
questa maniera è equivalente a \func{wait}.\\
$0$ & \const{WAIT\_MYPGRP} & attende per un figlio il cui \textit{process
group} è uguale a quello del processo chiamante. \\
$>0$ & -- &attende per un figlio il cui \acr{pid} è uguale al
- valore di \var{pid}.\\
+ valore di \param{pid}.\\
\hline
\end{tabular}
- \caption{Significato dei valori del parametro \var{pid} della funzione
+ \caption{Significato dei valori dell'argomento \param{pid} della funzione
\func{waitpid}.}
\label{tab:proc_waidpid_pid}
\end{table}
In genere in un programma non si vuole essere forzati ad attendere la
conclusione di un processo per proseguire, specie se tutto questo serve solo
-per leggerne lo stato di chiusura (ed evitare la presenza di \textit{zombie}),
-per questo la modalità più usata per chiamare queste funzioni è quella di
-utilizzarle all'interno di un \textit{signal handler} (vedremo un esempio di
-come gestire \const{SIGCHLD} con i segnali in \secref{sec:sig_example}). In
-questo caso infatti, dato che il segnale è generato dalla terminazione di un
-figlio, avremo la certezza che la chiamata a \func{wait} non si bloccherà.
+per leggerne lo stato di chiusura (ed evitare la presenza di
+\textit{zombie}\index{zombie}), per questo la modalità più usata per chiamare
+queste funzioni è quella di utilizzarle all'interno di un \textit{signal
+ handler} (vedremo un esempio di come gestire \const{SIGCHLD} con i segnali
+in \secref{sec:sig_example}). In questo caso infatti, dato che il segnale è
+generato dalla terminazione di un figlio, avremo la certezza che la chiamata a
+\func{wait} non si bloccherà.
\begin{table}[!htb]
\centering
analizzare lo stato di uscita. Esse sono definite sempre in
\file{<sys/wait.h>} ed elencate in \tabref{tab:proc_status_macro} (si tenga
presente che queste macro prendono come parametro la variabile di tipo
-\ctyp{int} puntata da \var{status}).
+\ctyp{int} puntata da \param{status}).
Si tenga conto che nel caso di conclusione anomala il valore restituito da
\val{WTERMSIG} può essere confrontato con le costanti definite in
ormai deprecata in favore di \func{wait4}.
\end{functions}
\noindent
-la struttura \type{rusage} è definita in \file{sys/resource.h}, e viene
+la struttura \struct{rusage} è definita in \file{sys/resource.h}, e viene
utilizzata anche dalla funzione \func{getrusage} (vedi
\secref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
processo; la sua definizione è riportata in \figref{fig:sys_rusage_struct}.
\end{prototype}
La funzione \func{exec} esegue il file o lo script indicato da
-\var{filename}, passandogli la lista di argomenti indicata da \var{argv}
-e come ambiente la lista di stringhe indicata da \var{envp}; entrambe le
+\param{filename}, passandogli la lista di argomenti indicata da \param{argv}
+e come ambiente la lista di stringhe indicata da \param{envp}; entrambe le
liste devono essere terminate da un puntatore nullo. I vettori degli
argomenti e dell'ambiente possono essere acceduti dal nuovo programma
quando la sua funzione \func{main} è dichiarata nella forma
riferimento allo specchietto riportato in \tabref{tab:proc_exec_scheme}. La
prima differenza riguarda le modalità di passaggio dei parametri che poi
andranno a costituire gli argomenti a linea di comando (cioè i valori di
-\var{argv} e \var{argc} visti dalla funzione \func{main} del programma
+\param{argv} e \param{argc} visti dalla funzione \func{main} del programma
chiamato).
Queste modalità sono due e sono riassunte dagli mnemonici \code{v} e \code{l}
La seconda differenza fra le funzioni riguarda le modalità con cui si
specifica il programma che si vuole eseguire. Con lo mnemonico \code{p} si
indicano le due funzioni che replicano il comportamento della shell nello
-specificare il comando da eseguire; quando il parametro \var{file} non
+specificare il comando da eseguire; quando il parametro \param{file} non
contiene una \file{/} esso viene considerato come un nome di programma, e
viene eseguita automaticamente una ricerca fra i file presenti nella lista di
directory specificate dalla variabile di ambiente \var{PATH}. Il file che
\errcode{EACCES}.
Le altre quattro funzioni si limitano invece a cercare di eseguire il file
-indicato dal parametro \var{path}, che viene interpretato come il
+indicato dall'argomento \param{path}, che viene interpretato come il
\textit{pathname} del programma.
\begin{figure}[htb]
L'effetto della chiamata è diverso a seconda dei privilegi del processo; se
l'\textsl{userid effettivo} è zero (cioè è quello dell'amministratore di
sistema) allora tutti gli identificatori (\textit{real}, \textit{effective} e
-\textit{saved}) vengono impostati al valore specificato da \var{uid},
+\textit{saved}) vengono impostati al valore specificato da \param{uid},
altrimenti viene impostato solo l'\textsl{userid effettivo}, e soltanto se il
valore specificato corrisponde o all'\textsl{userid reale} o
all'\textsl{userid salvato}. Negli altri casi viene segnalato un errore (con
\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Imposta l'\textsl{userid
reale} e l'\textsl{userid effettivo} del processo corrente ai valori
-specificati da \var{ruid} e \var{euid}.
+specificati da \param{ruid} e \param{euid}.
\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Imposta il \textsl{groupid
reale} ed il \textsl{groupid effettivo} del processo corrente ai valori
-specificati da \var{rgid} e \var{egid}.
+specificati da \param{rgid} e \param{egid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore possibile è \errval{EPERM}.}
\headdecl{sys/types.h}
\funcdecl{int seteuid(uid\_t uid)} Imposta l'userid effettivo del processo
-corrente a \var{uid}.
+corrente a \param{uid}.
\funcdecl{int setegid(gid\_t gid)} Imposta il groupid effettivo del processo
-corrente a \var{gid}.
+corrente a \param{gid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore è \errval{EPERM}.}
\headdecl{sys/types.h}
\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Imposta
-l'userid reale, l'userid effettivo e l'userid salvato del processo corrente
-ai valori specificati rispettivamente da \var{ruid}, \var{euid} e \var{suid}.
+l'userid reale, l'userid effettivo e l'userid salvato del processo corrente ai
+valori specificati rispettivamente da \param{ruid}, \param{euid} e
+\param{suid}.
\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Imposta il
groupid reale, il groupid effettivo ed il groupid salvato del processo
-corrente ai valori specificati rispettivamente da \var{rgid}, \var{egid} e
-\var{sgid}.
+corrente ai valori specificati rispettivamente da \param{rgid}, \param{egid} e
+\param{sgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore è \errval{EPERM}.}
\headdecl{sys/fsuid.h}
\funcdecl{int setfsuid(uid\_t fsuid)} Imposta l'userid di filesystem del
-processo corrente a \var{fsuid}.
+processo corrente a \param{fsuid}.
\funcdecl{int setfsgid(gid\_t fsgid)} Imposta il groupid di filesystem del
-processo corrente a \var{fsgid}.
+processo corrente a \param{fsgid}.
\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
di fallimento: l'unico errore possibile è \errval{EPERM}.}
\textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\
\hline
\hline
- \textbf{Runnable} & \texttt{R} & Il processo è in esecuzione o è pronto ad
- essere eseguito (cioè è in attesa che gli venga assegnata la CPU). \\
- \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
- risposta dal sistema, ma può essere interrotto da un segnale. \\
- \textbf{Uninterrutible Sleep} & \texttt{D} & Il processo è in
- attesa di un risposta dal sistema (in genere per I/O), e non può essere
- interrotto in nessuna circostanza. \\
+ \textbf{Runnable}& \texttt{R} & Il processo è in esecuzione o è pronto ad
+ essere eseguito (cioè è in attesa che gli
+ venga assegnata la CPU). \\
+ \textbf{Sleep} & \texttt{S} & Il processo processo è in attesa di un
+ risposta dal sistema, ma può essere
+ interrotto da un segnale. \\
+ \textbf{Uninterrutible Sleep}& \texttt{D} & Il processo è in
+ attesa di un risposta dal sistema (in
+ genere per I/O), e non può essere
+ interrotto in nessuna circostanza. \\
\textbf{Stopped} & \texttt{T} & Il processo è stato fermato con un
- \const{SIGSTOP}, o è tracciato.\\
- \textbf{Zombie} & \texttt{Z} & Il processo è terminato ma il suo stato di
- terminazione non è ancora stato letto dal padre. \\
+ \const{SIGSTOP}, o è tracciato.\\
+ \textbf{Zombie}\index{zombie} & \texttt{Z} & Il processo è terminato ma il
+ suo stato di terminazione non è ancora
+ stato letto dal padre. \\
\hline
\end{tabular}
\caption{Elenco dei possibili stati di un processo in Linux, nella colonna
una fetta) per il quale esso deve essere eseguito. Il valore della
\textit{time-slice} è controllato dalla cosiddetta \textit{nice} (o
\textit{niceness}) del processo. Essa è contenuta nel campo \var{nice} di
-\var{task\_struct}; tutti i processi vengono creati con lo stesso valore, ed
-essa specifica il valore della durata iniziale della \textit{time-slice} che
-viene assegnato ad un altro campo della struttura (\var{counter}) quando il
-processo viene eseguito per la prima volta e diminuito progressivamente ad
+\struct{task\_struct}; tutti i processi vengono creati con lo stesso valore,
+ed essa specifica il valore della durata iniziale della \textit{time-slice}
+che viene assegnato ad un altro campo della struttura (\var{counter}) quando
+il processo viene eseguito per la prima volta e diminuito progressivamente ad
ogni interruzione del timer.
Quando lo scheduler\index{scheduler} viene eseguito scandisce la coda dei
\begin{prototype}{sched.h}
{int sched\_setscheduler(pid\_t pid, int policy, const struct sched\_param *p)}
Imposta priorità e politica di scheduling per il processo \param{pid}.
-
- \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
- errore, nel qual caso \var{errno} può assumere i valori:
+
+ \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso
+ di errore, nel qual caso \var{errno} può assumere i valori:
\begin{errlist}
\item[\errcode{ESRCH}] il processo \param{pid} non esiste.
- \item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il relativo
- valore di \param{p} non è valido.
+ \item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il
+ relativo valore di \param{p} non è valido.
\item[\errcode{EPERM}] il processo non ha i privilegi per attivare la
politica richiesta (vale solo per \const{SCHED\_FIFO} e
\const{SCHED\_RR}).
\label{tab:proc_sched_policy}
\end{table}
-Il valore della priorità è passato attraverso la struttura \var{sched\_param}
-(riportata in \figref{fig:sig_sched_param}), il cui solo campo attualmente
-definito è \var{sched\_priority}, che nel caso delle priorità assolute deve
-essere specificato nell'intervallo fra un valore massimo ed uno minimo, che
-nel caso sono rispettivamente 1 e 99 (il valore zero è legale, ma indica i
-processi normali).
+Il valore della priorità è passato attraverso la struttura
+\struct{sched\_param} (riportata in \figref{fig:sig_sched_param}), il cui solo
+campo attualmente definito è \var{sched\_priority}, che nel caso delle
+priorità assolute deve essere specificato nell'intervallo fra un valore
+massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99 (il valore
+zero è legale, ma indica i processi normali).
\begin{figure}[!htb]
\footnotesize \centering
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{La struttura \var{sched\_param}.}
+ \caption{La struttura \structd{sched\_param}.}
\label{fig:sig_sched_param}
\end{figure}
\end{prototype}
La funzione restituisce il valore dell'intervallo di tempo usato per la
-politica \textit{round robin} in una struttura \var{timespec}, (la cui
+politica \textit{round robin} in una struttura \struct{timespec}, (la cui
definizione si può trovare in \figref{fig:sys_timeval_struct}).
atomici. Non è affatto detto che lo stesso valga per interi di dimensioni
maggiori (in cui l'accesso può comportare più istruzioni in assembler) o per
le strutture. In tutti questi casi è anche opportuno marcare come
-\ctyp{volatile} le variabili che possono essere interessate ad accesso
+\direct{volatile} le variabili che possono essere interessate ad accesso
condiviso, onde evitare problemi con le ottimizzazioni del codice.
\subsection{Le \textit{race condition}\index{race condition} e i
- \textit{deadlock}}
+ \textit{deadlock}\index{deadlock}}
\label{sec:proc_race_cond}
Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
problematiche di questo tipo in \capref{cha:IPC}).
Un caso particolare di \textit{race condition} sono poi i cosiddetti
-\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
-completo di un servizio, e non il fallimento di una singola operazione. Per
-definizione un \textit{deadlock} è una situazione in cui due o più processi
-non sono più in grado di proseguire perché ciascuno aspetta il risultato di
-una operazione che dovrebbe essere eseguita dall'altro.
-
-
-L'esempio tipico di una situazione che può condurre ad un \textit{deadlock} è
-quello in cui un flag di ``occupazione'' viene rilasciato da un evento
-asincrono (come un segnale o un altro processo) fra il momento in cui lo si è
-controllato (trovandolo occupato) e la successiva operazione di attesa per lo
-sblocco. In questo caso, dato che l'evento di sblocco del flag è avvenuto
-senza che ce ne accorgessimo proprio fra il controllo e la messa in attesa,
-quest'ultima diventerà perpetua (da cui il nome di \textit{deadlock}).
+\textit{deadlock}\index{deadlock}, particolarmente gravi in quanto comportano
+spesso il blocco completo di un servizio, e non il fallimento di una singola
+operazione. Per definizione un \textit{deadlock}\index{deadlock} è una
+situazione in cui due o più processi non sono più in grado di proseguire
+perché ciascuno aspetta il risultato di una operazione che dovrebbe essere
+eseguita dall'altro.
+
+
+L'esempio tipico di una situazione che può condurre ad un
+\textit{deadlock}\index{deadlock} è quello in cui un flag di ``occupazione''
+viene rilasciato da un evento asincrono (come un segnale o un altro processo)
+fra il momento in cui lo si è controllato (trovandolo occupato) e la
+successiva operazione di attesa per lo sblocco. In questo caso, dato che
+l'evento di sblocco del flag è avvenuto senza che ce ne accorgessimo proprio
+fra il controllo e la messa in attesa, quest'ultima diventerà perpetua (da cui
+il nome di \textit{deadlock}\index{deadlock}).
In tutti questi casi è di fondamentale importanza il concetto di atomicità
visto in \secref{sec:proc_atom_oper}; questi problemi infatti possono essere