Archive for luglio, 2009
Threads, Mutex e Semafori in C – La programmazione concorrente – Mutua esclusione
luglio 4, 2009 11:35 am
Abbiamo esaminato un listato inerente la programmazione concorrente, ma, obiettivamente, il listato presentato è puramente accademico, in quanto non solo non reputo personalmente utile utilizzare due thread per una printf, ma non credo sarebbe servito direttamente il programma.
Fatta questa (dovuta) premessa, continuiamo la trattazione facendo vedere il REALE motivo per cui si lavora in programmazione concorrente, ovvero l’accesso alla memoria condivisa.
#include
#include
#include#define MAX 10 pthread_mutex_t M; /* def.mutex condiviso tra threads */
int DATA=0; /* variabile condivisa */
int accessi1=0; /*num. di accessi del thread 1 alla sez critica */
int accessi2=0; /*num. di accessi del thread 2 alla sez critica */void *thread1_process (void * arg)
{ int k=1;
while(k)
{
pthread_mutex_lock(&M); /*prologo */
accessi1++;
DATA++;
k=(DATA>=MAX?0:1);
printf(“accessi di T1: %d\n”, accessi1);
pthread_mutex_unlock(&M); /*epilogo */
sleep(1);
}
pthread_exit (0);
}void *thread2_process (void * arg)
{ int k=1;
while(k)
{
pthread_mutex_lock(&M); /*prologo sez. critica */
accessi2++;
DATA++;
k=(DATA>=MAX?0:1);
printf(“accessi di T2: %d\n”, accessi2);
pthread_mutex_unlock(&M); /*epilogo sez. critica*/
sleep(1);
}
pthread_exit (0);
}int main ()
{ pthread_t th1, th2;
/* il mutex e` inizialmente libero: */
pthread_mutex_init (&M, NULL);
if (pthread_create(&th1, NULL, thread1_process, NULL) < 0)
{ fprintf (stderr, "create error for thread 1\n");
exit (1);
}
if (pthread_create(&th2, NULL,thread2_process,NULL) < 0)
{ fprintf (stderr, "create error for thread 2\n");
exit (1);
}
pthread_join (th1, NULL);
pthread_join (th2, NULL);printf("Accessi: T1: %d, T2 %d\n",accessi1,accessi2);
}
Commentiamo il codice dall’inizio.
La priam parte è scontata, sono gli include, chi vuole vederseli vada pure qui. Dopo, definiamo una macro, che attribuisce a MAX il valore dieci per tutto il programma. (Adoro le macro di sostituzione, permettono al C di trasformarsi in qualsiasi cosa )
inizializziamo un MUTEX, tramite la variabile pthread_mutex_t, mentre DATA rappresenterà la nostra variabile condivisa. Accessi1 e Accessi2 ci mostreranno il numero di volte che i due threads accederanno alla memoria condivisa.
Cominciamo con le funzioni, che sono molto simili tra di loro come struttura, ma agiscono su variabili diverse in alcune parti.
La funzione *thread1_process inizializza una variabile k, ponendola pari ad 1, e crea un ciclo while con k funzione chiusura del ciclo.
Il ciclo è composto da:
* Lock del mutex tramite la funzione pthread_mutex_lock che accetta come argomento un riferimento ad un mutex.
* incremento degli accessi del thread e della variabile DATA
* Se data ha raggiunto il valore massimo allora il flag k diventa zero e il ciclo non si ripeterà.
* Stampa del numero di accessi
* Sblocco del mutex
Anche *thread2_process esegue un ciclo identico.
Il main alla fine effettua le seguenti operazioni:
* Crea due thread
* Inizializza il mutex creato, che inizialmente è libero
* Lancia la create per i due thread e su entrambi effettua un controllo d’errore.
* Effettua il join dei due threads
Categories: Articoli didattici.. o quasi!
No Comments »
Threads, Mutex e Semafori in C – La programmazione concorrente
luglio 2, 2009 11:20 am
Ebbene si, sono tornato a studiare.
Dopo il tormento elettrotecnica, si passa a sistemi operativi, una materia molto bella ma molto ostica, che mi “costringerà” nel poco tempo che ho a disposizione, a studiare la programmazione concorrente in C.
Chiunque mi conosca un minimo, sia tramite il mio blog che di presenza, sa che non sono un eccellente programmatore, specialmente in C, anche se mi piace abbastanza programmare, quando mi ci metto.
Tempo fa parlai di alberi binari, adesso parliamo di thread.
Un thread è la più piccola unità di utilizzo della CPU, contenuta all’interno di un processo, che può agire contemporaneamente ad altri thread, chiamati appunto concorrenti.
Un linguaggio di programmazione che fa uso di threads, è detto concorrente.
Non scendo al momento nel dettaglio sul perchè i threads siano utili e a cosa servano.. vediamo qualche semplice esempio di listati sui threads, ovvero come crearli, joinarli e distruggerli, ma soprattutto, come farli cooperare.
#include
#includevoid *funzionebanale1(void * arg)
{
printf (“Thread numero 1 in azione\n”);
pthread_exit (0);
}
void *funzionebanale2(void * arg)
{
printf (“Thread numero 2 in azione\n”);
pthread_exit (0);
}int main(void * args)
{
pthread_t tid1, tid2;
pthread_create(&tid1,NULL,funzionebanale1,NULL);
pthread_create(&tid2,NULL,funzionebanale2,NULL);
pthread_join (tid1, NULL);
printf(“terminato il thread 1\n”);
pthread_join (tid2, NULL);
printf(“terminato il thread 2\n”);
return 0;
}
Vediamo di esaminare un pò questo listato.
La prima parte, gli include, sono più che noti a chi ha un minimo di dimestichezza con il linguaggio C, andiamo quindi immediatamente alla parte successiva.
Quello che vediamo sono due funzioni molto semplici (non per niente chiamate funzionibanali) che restituiscono un puntatore a void, e che accettano un puntatore a void come argomento.
Le funzioni si limitano a stampare a video una scritta con una semplice printf e a richiamare una funzione, chiamata pthread_exit con parametro 0, che permette di chiudere un thread senza rilasciare errori.
Andiamo quindi al main.
Un thread va INIZIALIZZATO come una qualsiasi variabile, in questo caso il tipo è pthread_t, per cui creiamo due threads, chiamandoli tid1 e tid2.
A questo punto possiamo effettivamente creare il thread vero e proprio, utilizzando la funzione pthread_create
La funzione pthread_create accetta quattro argomenti, il primo è un riferimento alla variabile pthread_t su cui si lavora, il secondo è invece un riferimento ad una variabile di tipo pthread_attr_t che identifica gli attributi che deve avere il thread. Impostando tale secondo attributo a NULL, si utilizzeranno i valori di default, caso abbastanza classico.
Il terzo attributo rappresenta un puntatore alla funzione che contiene il codice che deve eseguire il thread.
Il quarto attributo rappresenta l’attbuto che viene passato alla funzione precedentemente puntata. Se la funzione può anche non accettare argomenti, si può impostare un simpatico NULL.
Una volta creati i due thread, occorre joinare.
La funzione pthread_join sospende l’esecuzione del thread chiamante fintantochè non è completato il codice del thread chiamato. La funzione accetta come argomenti un thread e un puntatore doppio, nella quale variabile puntata sarà inserito il valore di ritorno del thread chiamato.
Categories: Articoli didattici.. o quasi!
No Comments »
