<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//IT">
<HTML>
<HEAD>
 <META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 <META NAME="GENERATOR" CONTENT="lfparser_2.29">
 <META NAME="LFCATEGORY" CONTENT="SoftwareDevelopment">
 <TITLE>lf272, SoftwareDevelopment: Programmazione concorrente - Principi e introduzione ai processi</TITLE>
<style type="text/css">
<!--
 td.top {font-family: Arial,Geneva,Verdana,Helvetica,sans-serif; font-size:12 }
 pre { font-family:monospace,Courier }
 p.cl { color:#EE9500 }
 a.nodec { text-decoration:none }
 p.trans { font-size:8pt; text-align:right }
 p.clbox { width:50%; alignment:center; background-color:#FFD700; 
           border-style:none; border-width:medium; border-color:#FFD700; 
           padding:0.5cm;  text-align:center }
 p.code { width:80%; alignment:center; background-color:#aedbe8; 
          border-style:none; border-width:medium; border-color:#aedbe8; 
          padding:0.1cm;  text-align:left }
 p.foot { background-color:#AAAAAA; color:#FFFFFF; border-style:none; 
          border-width:medium; border-color:#AAAAAA; padding:0.5cm ; 
          margin-top:0.1cm; margin-right:1cm; margin-left:1cm; 
          text-align:center }
 .mark  { background-color:#e6e6ff }
-->
</style>
 
</HEAD>
<BODY bgcolor="#ffffff" text="#000000">
 <!-- this is generated html code. NEVER use this file for your
 translation work. Instead get the file with the same article number
 and .meta.shtml in its name. Translate this meta file and then
 use lfparser program to generate the final article -->
 <!-- lfparser can be obtained from http://www.linuxfocus.org/~guido/dev/lfparser.html -->

<!-- this is used by a number of tools:
 =LF=AUTHOR: Leonardo Giordani
 =LF=CAT___: SoftwareDevelopment
 =LF=TITLE_: Programmazione concorrente - Principi e introduzione ai processi
 =LF=NUMBER: 272
 =LF=ANAME_: article272.shtml
 -->

<!-- 2pdaIgnoreStart -->

<!-- start navegation bar -->
 <!-- top navegation bar -->
 <TABLE summary="topbar_1" cellspacing="0" cellpadding="0" border="0" align="center" width="90%">
   <TR bgcolor="#2e2292">
     <TD class="top"><TABLE summary="topbar_1_logo" cellspacing="0" cellpadding="0" border="0" width=
       "100%">
         <TR><TD width="319"><IMG src="../../common/images/logolftop_319x45.gif"
           alt="[LinuxFocus-icon]" width="319" height="45" align="left" 
           border="0"></TD>

           <TD class="top">
             <TABLE summary="topbar_1_links" width="100%">
               <TR align="right">
                 <TD class="top"><A class="nodec" href="../index.shtml"><FONT color=
                 "#DDDDDD" size="2">Home</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../map.html"><FONT color=
                 "#DDDDDD" size="2">Mappa</FONT></A> &nbsp;|&nbsp; <A class=
                 "nodec" href="../indice.html"><FONT color=
                 "#DDDDDD" size="2">Indice</FONT></A> &nbsp;|&nbsp; <A class="nodec" href="../Search/index.shtml"><FONT color=
                 "#DDDDDD" size="2">Cerca</FONT></A> </TD>
               </TR>

               <TR align="right">
                 <TD class="top">
                   <HR width="100%" noshade size="1">
                 </TD>
               </TR>
             </TABLE>
           </TD>
         </TR>
       </TABLE>
     </TD>
   </TR>
 </TABLE>
 <!-- end top navegation bar -->
 <!-- blue bar -->
 <TABLE summary="topbar_2" cellspacing="0" cellpadding="0" border="0" align="center"
 width="90%">
   <TR bgcolor="#00ffff">
     <TD><IMG src="../../common/images/transpix.gif" width="1" height=
     "2" alt=""></TD>
   </TR>
 </TABLE>
 <!-- end blue bar -->
 <!-- bottom navegation bar -->
 <TABLE summary="topbar_3" cellspacing="0" cellpadding="0" border="0" align="center"
 width="94%">
   <TR bgcolor="#000000">
     <TD>
       <TABLE summary="topbar_3_links" cellspacing="0" cellpadding="1" border="0" width=
       "100%">
         <TR align="center">
           <TD WIDTH="20%"><A class="nodec" href="../News/index.shtml"><FONT color=
           "#FFFFFF">News</FONT></A> </TD>
           <TD WIDTH="5%"><FONT color="#FFFFFF">|</FONT> </TD>
           <TD WIDTH="20%"><A class="nodec" href="../Archives/index.html"><FONT color=
           "#FFFFFF">Archivo</FONT></A> </TD>
           <TD WIDTH="5%"><FONT color="#FFFFFF">|</FONT> </TD>
           <TD WIDTH="20%"><A class="nodec" href="../Links/index.html"><FONT color=
           "#FFFFFF">Link</FONT></A> </TD>
           <TD WIDTH="5%"><FONT color="#FFFFFF">|</FONT> </TD>
           <TD WIDTH="20%"><A class="nodec" href="../aboutus.html"><FONT color=
           "#FFFFFF">Cose LF</FONT></A> </TD>
         </TR>
       </TABLE>
     </TD>
   </TR>
 </TABLE>
 <!-- end bottom navegation bar -->
<!-- stop navegation bar -->

<!-- SSI_INFO -->

<!-- tr_staticssi include virtual -->
<!-- tr_staticssi exec cmd -->
<!-- addedByLfdynahead ver 1.4 --><TABLE ALIGN="right" border=0><TR><TD ALIGN="right"><FONT SIZE="-1" FACE="Arial,Helvetica">Questo documento &egrave; disponibile in: <A href="../../English/November2002/article272.shtml">English</a> &nbsp;<A href="../../Castellano/November2002/article272.shtml">Castellano</a> &nbsp;<A href="../../ChineseGB/November2002/article272.shtml">ChineseGB</a> &nbsp;<A href="../../Deutsch/November2002/article272.shtml">Deutsch</a> &nbsp;<A href="../../Francais/November2002/article272.shtml">Francais</a> &nbsp;<A href="../../Italiano/November2002/article272.shtml">Italiano</a> &nbsp;<A href="../../Nederlands/November2002/article272.shtml">Nederlands</a> &nbsp;<A href="../../Russian/November2002/article272.shtml">Russian</a> &nbsp;<A href="../../Turkce/November2002/article272.shtml">Turkce</a> &nbsp;<A href="../../Polish/November2002/article272.shtml">Polish</a> &nbsp;</FONT></TD></TR></TABLE><br>
 


<!-- SSI_INFO STOP -->
<!-- 2pdaIgnoreStop -->

<!-- SHORT BIO ABOUT THE AUTHOR -->
<TABLE ALIGN=LEFT BORDER=0  WIDTH="190" summary="about the author">
<TR>
<TD>

<!-- 2pdaIgnoreStart -->
<!-- PALM DOC -->
<TABLE BORDER=0 hspace=4 vspace=4 summary="pda download"> <TR> <TD>
<font size=1> <img src="../../common/images/2doc.gif" width=34 align=left border=0 height=22 alt="convert to palm"><a href="http://cgi.linuxfocus.org/cgi-bin/2ztxt">Convert to GutenPalm</a><br>or <a href="http://cgi.linuxfocus.org/cgi-bin/2pda">to PalmDoc</a></font>
</TD> </TR> </TABLE>
<!-- END PALM DOC -->
<!-- 2pdaIgnoreStop -->
<br>
<img src="../../common/images/LeonardoGiordani.jpg" width="85" height="109" alt="[Leonardo]">
<BR>   Leonardo Giordani <br> <small>&lt;leo.giordani(at)libero.it&gt;</small>
<BR><BR>
<I>L'autore:</I><BR>
<P> Studente presso la Facolt&agrave; di Ingegneria delle Telecomunicazioni del Politecnico
di Milano, si occupa di amministrazione di rete e di programmazione (prevalentemente in
Assembly e C/C++). Ha conosciuto la realt&agrave; di Linux/Unix nel 1999 e da allora si dedica
quasi esclusivamente ad essa.</P>
<!-- TRANSLATED TO it -->
<!-- TRANSLATED TO STOP -->
<BR><i>Contenuto</i>:
<UL>
  <LI><A HREF="#272lfindex0">Introduzione</A></LI>
  <LI><A HREF="#272lfindex1">Il concetto di processo</A></LI>
  <LI><A HREF="#272lfindex2">I processi in Linux e Unix</A></LI>
  <LI><A HREF="#272lfindex3">Multitasking nella libc</A></LI>
  <LI><A HREF="#272lfindex4">Letture raccomandate</A></LI>
  <LI><A HREF="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=272&amp;lang=en">Discussioni su quest'articolo</A></LI>
</UL>

</TD></TR></TABLE>
<!-- HEAD OF THE ARTICLE -->
<br>&nbsp;
<H2>Programmazione concorrente - Principi e introduzione ai processi</H2>
 <img src="../../common/images/illustration272.jpg" width="300" height="180" alt="[run in paralell]">
<!-- ABSTRACT OF THE ARTICLE -->
<P><i>Premessa</i>:
<P>


Questa serie di articoli vuole introdurre il lettore al principio di multitasking
e alla sua implementazione nel sistema operativo Linux. Partendo dai concetti
teorici che stanno alla base del multitasking si arriver&agrave; a scrivere una completa
applicazione dimostrativa della comunicazione tra processi, con un semplice ma
efficace protocollo di comunicazione.<br>

Prerequisiti per la comprensibilit&agrave; dell'articolo sono:<br><ul><li>Conoscenza minimale dell'uso della shell
<li>Conoscenza base del C (sintassi, cicli, librerie)
</ul>

Tutti i riferimenti alle pagine di manuale sono posti tra parentesi dopo il nome
del comando citato. Tutte le funzioni della glibc sono documentate tramite "info Libc".


<br>
<br><!-- HR divider --><center><font color="#8282e0"><b>_________________ _________________ _________________</b></font></center><br> 
<!-- BODY OF THE ARTICLE -->


<A NAME="272lfindex0">&nbsp;</A>
<H3>Introduzione</H3>


Una delle svolte pi&ugrave; importanti che si sono avute nella storia dei sistemi operativi
&egrave; stata l'introduzione del concetto di multiprogrammazione, un metodo per
interallacciare l'esecuzione di diversi programmi permettendo un utilizzo pi&ugrave;
intenso e costante delle risorse di sistema. Pensiamo anche solo ad una comune
workstation, dove un utente pu&ograve; avere in esecuzione contemporaneamente un wordprocessor,
un riproduttore audio, una coda di stampa, un navigatore web e chi pi&ugrave; ne ha pi&ugrave; ne
metta, e ci renderemo subito conto dell'importanza pratica di questa
tecnica. Come scopriremo pi&ugrave; avanti, poi, questa piccola lista non &egrave; che una parte
(minima) dell'insieme di programmi realmente in esecuzione sulla
nostra macchina, nonostante sia la parte pi&ugrave; "appariscente".

<A NAME="272lfindex1">&nbsp;</A>
<H3>Il concetto di processo</H3>


<p>
Per poter effettuare l'interallacciamento dei programmi &egrave; necessario complicare
notevolmente il sistema operativo; per poter evitare che ci siano conflitti tra
i vari programmi &egrave; obbligatorio incapsulare ognuno di essi assieme a tutte le
informazioni necessarie per la sua esecuzione.

<p>
Volendo dare un po' di nomenclatura tecnica diciamo che, dato un <b>PROGRAMMA</b>
in esecuzione, in un certo istante &egrave; detto <b>CODICE</b> l'insieme delle
istruzioni che lo compongono, <b>SPAZIO DI MEMORIA</b> l'attuale insieme
di memoria della macchina occupato dai suoi dati e <b>STATO DEL PROCESSORE</b>
l'insieme dei valori dei parametri del microprocessore, quali le flag o il
Program Counter (l'indirizzo della prossima istruzione da eseguire).

<p>
Data una terna ci oggetti composta da CODICE, SPAZIO DI MEMORIA e STATO
DEL PROCESSORE abbiamo univocamente definito un <b>PROGRAMMA IN
ESECUZIONE</b>. Se quindi ad un certo momento durante il funzionamento
della macchina salvassimo queste informazioni e le sostituissimo con
altre relative ad un'altro programma il flusso di quest'ultimo proseguirebbe
dal punto in cui era stato arrestato e noi avremmo realizzato
l'interallacciamento di cui parlavamo prima. La terna di oggetti che
abbiamo identificato ora &egrave; detta <b>PROCESSO</b> o <b>TASK</b>, concetto che quindi
ha a che fare con quello di programma, ma che ne un'estensione.

<p>
Possiamo ora formalizzare ci&ograve; che accade alla workstation di cui parlavamo
nell'introduzione: in ogni istante di tempo &egrave; in esecuzione un
solo processo (c'&egrave; un solo microprocessore), e la macchina esegue parte del
codice di quest'ultimo; dopo un certo istante di tempo molto breve
detto QUANTO il processo in esecuzione viene sospeso e le sue informazioni
sono salvate e sostituite con quelle relative ad un altro processo in
attesa, il cui codice viene eseguito per un altro quanto di tempo e cos&igrave; via.
Agli occhi dell'utente questo realizza la CONCORRENZA dei processi,
ovvero l'esecuzione simultanea di pi&ugrave; programmi.

<p>
L'introduzione del multitasking (o multiprogrammazione) crea un insieme di
problemi non banali, come la gestione delle code dei processi in
attesa (SCHEDULING), che per&ograve; riguardano pi&ugrave; strettamente l'architettura di
un singolo sistema operativo. Non &egrave; escluso che in un futuro
articolo si parli anche di questo, magari guardando pi&ugrave; da vicino il codice
del kernel.

<A NAME="272lfindex2">&nbsp;</A>
<H3>I processi in Linux e Unix</H3>


<p>
Prima di avventurarci nella scrittura di codice multiprogrammato vediamo
cosa possiamo scoprire riguardo ai processi che gi&agrave; sono in
esecuzione sul nostro sistema; il comando che ci permette di avere queste
informazioni &egrave; <b>ps(1)</b> che sta per "process status", stato dei
processi. Aprendo una normale shell testuale e digitando il comando ps
otterremo un output simile al seguente:

<pre>
  PID TTY          TIME CMD
 2241 ttyp4    00:00:00 bash
 2346 ttyp4    00:00:00 ps
</pre>

<p>
Premetto subito che questo elenco non &egrave; affatto completo, ma per adesso
accontentiamoci di questo: ps ci ha restituito l'elenco di tutti
i processi che sono stati lanciati dal terminale corrente. Vediamo subito
che l'ultima colonna riporta il nome del comando che &egrave; stato dato
per lanciare quel dato processo: ovviamente ps compare nell'elenco in quanto
nell'istante in cui &egrave; stato lanciato &egrave; entrato nella lista dei
processi in esecuzione. L'altro processo &egrave; la bash, la shell che sto usando
sui miei terminali.

<p>
Tralasciamo per ora le informazioni TIME e TTY, e concentriamoci su PID, che
sta per Process IDentifier, ovvero identificatore di
processo. Il pid &egrave; un numero strettamente maggiore di zero che viene
assegnato univocamente ad ogni processo che viene eseguito; chiaramente
una volta terminato il processo il pid pu&ograve; essere riutilizzato, ma abbiamo
la garanzia che mentre il processo &egrave; in esecuzione il pid
non verr&agrave; cambiato. Questo implica che l'output che ognuno di voi avr&agrave; dal
comando ps sar&agrave; molto probabilmente diverso dal mio almeno per
quanto riguarda i valori del pid. Per renderci effettivamente conto di questo
proviamo ad aprire una nuova shell senza chiudere quella
precedente: l'output del comando ps questa volta riporta il processo "bash"
con il pid 2488 (o comunque differente da quello precedente),
testimoniando che a discapito del nome si tratta di due processi differenti,
nonostante il programma che eseguono sia uguale.

<p>
Vediamo ora come sia possibile ottenere una lista di tutti i processi
attualmente in esecuzione sulla nostra Linux box. La pagina di manuale
del comando ps (piuttosto corposa) riporta lo switch -e con la dizione
"select all processes". Proviamo quindi a digitare "ps -e" ed
otterremo una lista piuttosto lunga formattata in maniera analoga all'output
precedentemente analizzato. Per analizzare pi&ugrave; comodamente la
lista salviamo l'output in un file, che chiameremo ps.log:

<pre>
ps -e &gt; ps.log
</pre>

<p>
Adesso possiamo leggere con comodo il file utilizzando in nostro editor
preferito (o semplicemente il comando less); come anticipato il
numero di processi che sono in esecuzione &egrave; pi&ugrave; alto di quanto ci aspettassimo.
Notiamo infatti che in elenco non ci sono solamente
applicazioni lanciate da noi nell'ambiente grafico, bens&igrave; un insieme di
processi con nomi talora piuttosto oscuri: il numero e l'identit&agrave;
dei processi elencati dipende dalla configurazione del vostro sistema,
ma possiamo notare alcune cose comuni.
Innanzitutto tutti noteranno come il processo che ha il pid 1 sia <b>init(8)</b>:
questo non &egrave; un caso, ma fa parte dell'architettura di Linux. Il
processo init, infatti, &egrave; il padre di tutti i processi, per cui &egrave; il primo
ad essere eseguito. Un'altra cosa che tutti noteranno &egrave; la
presenza di molti processi il cui nome termina con una "d": sono i cosidetti
"demoni", e sono tra i processi pi&ugrave; importanti del sistema.
Approfondiremo il discorso su init e i demoni in un articolo successivo,
quindi per ora accontentiamoci di convivere con queste due entit&agrave;.

<A NAME="272lfindex3">&nbsp;</A>
<H3>Multitasking nella libc</H3>


<p>
Dopo aver compreso il concetto di processo ed aver visto velocemente
quanto esso sia importante nel sistema operativo possiamo procedere
oltre iniziando a scrivere codice multitasking; dalla banale esecuzione
simultanea di processi ci sposteremo poi verso una nuova
problematica: la comunicazione tra processi concorrenti e la loro
temporizzazione; vedremo due soluzioni molto eleganti al problema, i
messaggi ed i semafori, i secondi dei quali verranno poi approfonditi
nella trattazione dei thread. Inizieremo quindi a gettare le basi per
la scrittura di un'applicazione completa basata su questi concetti.

<p>
La libreria standard C (libc, implementata in Linux nella glibc del
progetto GNU) utilizza i meccanismi di multitasking implementati nello
Unix System V
(d'ora in poi SysV), uno Unix commerciale capostipite di una delle
due implementazioni pi&ugrave; famose di Unix; l'altra &egrave; BSD.

<p>
Nella libc viene definito il tipo pid_t come un integer contenente un pid.
D'ora in poi per contenere i pid dei processi utilizzeremo sempre
questo tipo di variabile, per un puro scopo di chiarezza: utilizzare come
variabile per i pid un int non presenta nessuna differenza.

<p>
Cominciamo a vedere quale funzione ci permette di conoscere il pid del
processo che contiene il nostro programma

<pre>
pid_t getpid (void)
</pre>

<p>
(contenuta insieme a pid_t negli header unistd.h e sys/types.h) e
scriviamo un programma che come scopo ha quello di stampare sullo standard
output il suo pid. Con un qualsiasi editor scrivete il seguente codice

<pre>
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;stdio.h&gt;

int main()
{
  pid_t pid;

  pid = getpid();
  printf("Il pid assegnato al processo &egrave; %d\n", pid);

  return 0;
}
</pre>

Salvate il programma come print_pid.c e compilatelo con

<pre>
gcc -o print_pid print_pid.c
</pre>

che creer&agrave; un eseguibile print_pid. Vi ricordo che se la directory
corrente non &egrave; nel path &egrave; necessario eseguire il programma come "./print_pid".
Eseguendo il programma non abbiamo particolari sorprese: esso stampa
un numero maggiore di zero e, se eseguito pi&ugrave; volte, &egrave; probabile che il
numero sia progressivo; questo non &egrave; obbligatorio, dato che potrebbe
esserci qualche altro processo che viene creato da un altro programma
tra un esecuzione e l'altra di print_pid. Provate ad esempio ad
eseguire ps tra due esecuzioni di print_pid...

<p>
Ora &egrave; tempo di imparare a creare un processo, ma &egrave; necessario spendere
ancora due parole su quello che avviene realmente durante questa
azione. Quando un programma (che &egrave; contenuto nel processo A) crea un
altro processo B i due sono identici, ovvero contengono lo stesso
codice, hanno la memoria piena degli stessi dati (non la stessa memoria,
ma due copie identiche della stessa) e hanno il medesimo stato del
processore. A questo punto i due si possono evolvere in maniere
indipendenti, per esempio in dipendenza degli input dell'utente o di fattori
casuali. Il processo A &egrave; detto "processo padre", mentre il B &egrave; il
"processo figlio"; adesso possiamo capire meglio l'attributo di "padre di
tutti i processi" dato a init. La funzione che crea un nuovo processo &egrave;

<pre>
pid_t fork(void)
</pre>

e deve il suo nome proprio all'azione di biforcare l'esecuzione del
programma. Il dato che viene restituito &egrave; un pid, ma merita una
considerazione molto particolare. Abbiamo detto che il processo
attuale si duplica in padre e figlio, che si interlacceranno nell'esecuzione
assieme agli altri processi del sistema, svolgendo due attivit&agrave;
differenti; ma subito dopo la creazione sar&agrave; in esecuzione il processo padre
o il processo figlio? Ebbene la risposta &egrave; semplice: uno dei due.
La decisione di quale processo deve venire eseguito viene infatti presa
da una parte di sistema operativo detta scheduler, il quale non bada
al fatto che un processo sia padre o figlio, ma segue un proprio
algoritmo indipendente basato su parametri prestazionali.

<p>
D'altronde &egrave; necessario sapere quale processo &egrave; in esecuzione, poich&eacute;
visto che il codice &egrave; lo stesso, entrambi i processi conterranno il
codice destinato al padre e quello destinato al figlio, ma ciascuno
di essi eseguir&agrave; solo quello destinato a s&eacute; stesso. Per chiarire
definitivamente il concetto seguiamo lo schema seguente:

<pre>
- BIFORCAZIONE
- SE SEI IL FIGLIO ESEGUI (...)
- SE SEI IL PADRE ESEGUI (...)
</pre>

che rappresenta in metalinguaggio il codice del nostro programma relativo
alla biforcazione.
Sveliamo quindi l'arcano: la funzione fork restituisce '0' al processo
figlio e il pid del figlio al processo padre. In questo modo baster&agrave;
che il programma testi se il pid restituito sia zero per sapere dentro
quale processo &egrave; in esecuzione. Il codice necessario ad effettuare
questa operazione &egrave; il seguente

<pre>
int main()
{
 pid_t pid;

 pid = fork();
 if (pid == 0)
 {
  CODICE PROCESSO FIGLIO
 }
 CODICE PROCSSO PADRE
}
</pre>

Vediamo allora il primo vero esempio di codice multitasking, che
potete salvare in un file fork_demo.c e compilare come per il programma
precedente. I numeri di riga sono stati ovviamente posti solamente per
la comprensione del codice. Il programma si biforcher&agrave; in due
ciascuno dei quali scriver&agrave; sullo schermo una stringa; eseguendolo ci
aspettiamo di ottenere un'interallacciamento dei due output.

<pre>
(01) #include &lt;unistd.h&gt;
(02) #include &lt;sys/types.h&gt;
(03) #include &lt;stdio.h&gt;

(04) int main()
(05) {
(05)   pid_t pid;
(06)   int i;

(07)   pid = fork();

(08)   if (pid == 0){
(09)     for (i = 0; i &lt; 8; i++){
(10)       printf("-FIGLIO-\n");
(11)     }
(12)     return 0;
(13)   }

(14)   for (i = 0; i &lt; 8; i++){
(15)     printf("+PADRE+\n");
(16)   }

(17)   return 0;
(18) }
</pre>

<p>
Le righe (01)-(03) contengono l'inclusione delle librerie necessarie
alle funzioni multitasking e all'I/O standard.<br>
Il main (04), come sempre in Linux, restituisce un intero che normalmente
&egrave; zero se il programma &egrave; terminato normalmente e un numero differente
da zero per indicare un qualche codice di errore, possibilit&agrave; che, per
semplicit&agrave;, abbiamo assunto non si possa verificare. Definiamo poi il
tipo di dato che contiene un pid (05) e un intero che funger&agrave; da contatore
per i cicli (06). In realt&agrave;, come abbiamo gi&agrave; detto, questi due
tipi sono identici, ma la loro differenziazione &egrave; utile a mantenere chiarezza.<br>
Alla riga (07) chiamiamo la funzione fork che restituir&agrave;, come abbiamo
gi&agrave; detto, un pid pari a zero nel programma eseguito nel processo
figlio e il pid del processo figlio nel programma eseguito nel processo
padre. Alla riga (08) testiamo proprio questo pid, cos&igrave; come abbiamo
spiegato prima. A questo punto il codice fino alla parentesi di riga
(13) verr&agrave; eseguito nel processo figlio, mentre il codice dalla riga
(14) alla (17) verr&agrave; eseguito nel processo padre.<br>
Il codice dalle righe dalla (09) alla (12) esegue un ciclo che stampa
8 volte la stringa "-FIGLIO-" e poi termina restituendo 0. Questo &egrave;
molto importante, poich&eacute; senza la riga (12) il figlio, una volta eseguito
il ciclo, proseguirebbe nell'esecuzione del ciclo successivo
(quello destinato al padre); errori di questo tipo sono estremamente
facili da compiere quando si scrive codice multitasking, ma altrettanto
difficili da trovare, visto che l'esecuzione di un programma di questo
tipo (soprattutto se complesso) porta a risultati differenti ad ogni
esecuzione, rendendo il debugging basato sui risultati quasi impossibile.<br>
Le righe dalla (14) alla (17) contengono il ciclo del processo padre,
che termina anch'esso con un "return 0".

<p>
Eseguendo il programma forse resteremo delusi: non posso assicurarvi
che il risultato sia una vera e propria mescolanza delle due stringhe,
e questo a causa della velocit&agrave; di esecuzione di un ciclo cos&igrave; breve
come quello da noi imposto; &egrave; molto probabile che ci&ograve; che otterremo
sar&agrave; una serie di stringhe "+PADRE+" seguite da una serie di stringhe
"-FIGLIO-" o il contrario. Provate comunque ad eseguire pi&ugrave; volte il
programma e il risultato potrebbe cambiare, anche se di poco.

<p>
Volendo avere un riscontro pi&ugrave; visuale del multitasking della nostra
applicazione potremmo pensare di inserire un ritardo casuale prima di
ogni chiamata a printf, mediante la funzione sleep e la funzione rand

<pre>
sleep (rand()%4)
</pre>

questo obbliga il programma ad attendere un numero casuale di secondi
tra 0 e 3 (il segno percentuale restituisce il resto della divisione
intera). Modifichiamo quindi i cicli inserendo questa riga prima della
(10) e della (15)

<pre>
(09)  for (i = 0; i &lt; 8; i++){
(->)    sleep (rand()%4);
(10)    printf("-FIGLIO-\n");
(11)  }
</pre>

A questo punto salviamo come fork_demo2.c, compiliamo ed eseguiamo.
A parte la lentezza notiamo anche una certa differenza nell'ordine delle
stringhe stampate a video, e una maggiore differenza da un'esecuzione
all'altra. Ci&ograve; che ottengo io, ad esempio, &egrave;

<pre>
[leo@mobile ipc2]$ ./fork_demo2
-FIGLIO-
+PADRE+
+PADRE+
-FIGLIO-
-FIGLIO-
+PADRE+
+PADRE+
-FIGLIO-
-FIGLIO-
+PADRE+
+PADRE+
-FIGLIO-
-FIGLIO-
-FIGLIO-
+PADRE+
+PADRE+
[leo@mobile ipc2]$
</pre>

<p>
Per terminare l'articolo diamo una scorsa alle problematiche che ci si
presentano di fronte ora: abbiamo la possibilit&agrave; di creare un certo
numero di processi figli dato un processo padre, in modo che essi eseguano
delle operazioni differenti da quelle del padre stesso in modo
concorrente; ma il processo padre spesso ha la necessit&agrave; di poter comunicare
con i processi figli, o almeno di sincronizzarsi con essi, in
modo che le operazioni vengano eseguite al momento opportuno. Ebbene vediamo
subito un primo modo di ottenere questa sincronizzazione tra
processi mediante la funzione di attesa

<pre>
pid_t waitpid (pid_t PID, int *STATUS_PTR, int OPTIONS)
</pre>

dove PID &egrave; il pid del processo di cui attendiamo il completamento,
STATUS_PTR un puntatore ad un intero che conterr&agrave; lo stato del processo
figlio (viene posto a NULL se l'informazione non serve) e OPTIONS un
insieme di opzioni che per ora possiamo trascurare.

Scriviamo quindi un esempio di programma in cui il padre crea il processo
figlio e ne attende il completamento

<pre>
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;stdio.h&gt;

int main()
{
  pid_t pid;
  int i;

  pid = fork();

  if (pid == 0){
    for (i = 0; i &lt; 14; i++){
      sleep (rand()%4);
      printf("-FIGLIO-\n");
    }
    return 0;
  }

  sleep (rand()%4);
  printf("+PADRE+ Attendo il completamento del processo figlio...\n");
  waitpid (pid, NULL, 0);
  printf("+PADRE+ ...terminato\n");

  return 0;
}
</pre>

Lo sleep nel codice del padre &egrave; stato inserito per differenziare l'esecuzione.
Salviamo il codice come fork_demo3.c compiliamo ed
eseguiamo. Abbiamo appena programmato la nostra prima applicazione
multitasking sincronizzata!

<p>
Nel prossimo articolo parleremo pi&ugrave; diffusamente della sincronizzazione
e della comunicazione tra processi cominciando a gettare le basi per
la nostra applicazione dimostrativa; per ora vi invito a scrivere dei
programmi che sfruttino le funzioni descritte, e ad inviarmeli di modo
che io possa utilizzarne alcuni per evidenziare soluzioni ingegnose o
errori da evitare. Vi prego di inviarmi sia il file .c con il codice
(commentato!) che un piccolo file di testo contenente una breve
descrizione del programma, il vostro nome e il vostro indirizzo di posta
elettronica. Buon lavoro!

<A NAME="272lfindex4">&nbsp;</A>
<H3>Letture raccomandate</H3>


<ul>
<li>Silberschatz, Galvin, Gagne, <b>Operating System Concepts -
	Sixth Edition</b>, Wiley&Sons, 2001
<li>Tanenbaum, WoodHull, <b>Operating Systems: Design and Implementation -
	Second Edition</b>, Prentice Hall, 2000
<li>Stallings, <b>Operating Systems - Fourth Edition</b>, Prentice Hall, 2002
<li>Bovet, Cesati, <b>Understanding the Linux Kernel</b>, O'Reilly, 2000
</ul>

<p>
Per segnalazioni o domande vi invito a scrivermi all'indirizzo
<a href="mailto:leo.giordani@libero.it">leo.giordani@libero.it</a>



<!-- 2pdaIgnoreStart -->
<A NAME="talkback">&nbsp;</a>
<h2>Discussioni su quest'articolo</h2>
ogni articolo possiede una sua pagina di discussione, da questa pagina puoi inviare un commento o leggere quelli degli altri lettori:
<center>
<table border="0"  CELLSPACING="2" CELLPADDING="1" summary="tb-button-outerpart">
 <tr BGCOLOR="#C2C2C2"><td align=center>
  <table border="3"  CELLSPACING="2" CELLPADDING="1" summary="tb-button">
   <tr BGCOLOR="#C2C2C2"><td align=center>
    <A href="http://cgi.linuxfocus.org/cgi-bin/lftalkback?anum=272&amp;lang=en"><b>&nbsp;pagina di discussione&nbsp;</b></a>
   </td></tr></table>
</td></tr></table>
</center>

<HR size="2" noshade>
<!-- ARTICLE FOOT -->
<CENTER><TABLE WIDTH="98%" summary="footer">
<TR><TD ALIGN=CENTER BGCOLOR="#9999AA" WIDTH="50%">
<A HREF="../../common/lfteam.html">Webpages maintained by the LinuxFocus Editor team</A>
<BR><FONT COLOR="#FFFFFF">&copy; Leonardo Giordani, <a href="../../common/copy.html">FDL</a> <BR><a href="http://www.linuxfocus.org">LinuxFocus.org</a></FONT>
<BR><a href="http://cgi.linuxfocus.org/cgi-bin/lfcomment?lang=it&amp;article=article272.shtml" target="_TOP">Click here to report a fault or send a comment to LinuxFocus</A><BR></TD>
<TD BGCOLOR="#9999AA">
<!-- TRANSLATION INFO -->
<font size=2>Translation information:</font>
<TABLE summary="translators">
  <tr><td><font size="2">it --&gt; -- : Leonardo Giordani <small>&lt;leo.giordani(at)libero.it&gt;</small></font></td></tr>
</TABLE>
</TD>
</TR></TABLE></CENTER>
<p><font size=1>2002-12-27, generated by lfparser version 2.29</font></p>
<!-- 2pdaIgnoreStop -->
</BODY>
</HTML>