• Non ci sono risultati.

6 I Thread POSIX - Pthread

N/A
N/A
Protected

Academic year: 2021

Condividi "6 I Thread POSIX - Pthread"

Copied!
4
0
0

Testo completo

(1)

LABORATORIO SISTEMI OPERATIVI 1

6 I Thread POSIX - Pthread

Un thread ` e un “flusso di controllo” all’interno di un processo. Un processo pu ` o avere pi ` u thread in esecuzione, i quali condividono le risorse del processo (ad esempio la memoria). Lo standard POSIX definisce un’insieme di funzioni per la creazione e la sincronizzazione di thread.

Vediamo le principali:

• pthread create(thead, attr, start routine, arg) prende 4 argomenti:

1. pthread t * thread: un puntatore a pthread t, l’analogo di pid t. Attenzione che non sempre ` e implementato come un intero;

2. pthread attr t * attr: attributi del nuovo thread (vedere pthread attr init per maggiori dettagli);

3. void * (*start routine)(void *) il codice da eseguire;

4. void * arg eventuali argomenti da passare.

• pthread exit(void *retval) termina l’esecuzione di un thread restituendo retval;

• pthread join(pthread t th, void **thread return) attende la terminazione del thread th. Se ha successo, ritorna 0 e un puntatore al valore ritornato dal thread;

• pthread detach(pthread t th) se non si vuole attendere la terminazione di un thread allora si deve eseguire questa funzione che pone th in stato detached: nessun altro thread potr ` a attendere la sua terminazione con pthread join e quando terminer ` a le sue risorse verranno automaticamente rilasciate (un p ` o come i processi orfani).

• pthread t pthread self() ritorna il proprio thread id.

ATTENZIONE: questo ID dipende dall’implementazione ed ` e l’ID della libreria phread e non l’ID di sistema. Per visualizzare l’ID di sistema (quello che si osserva, ad esempio, con il comando ps -eLf) si pu ` o usare una syscall specifica di Linux syscall(SYS gettid).

Effettuare i seguenti test (NOTA Si deve compilare con l’opzione -lpthread)

1. Scrivere un programma che crea 2 thread i quali stampano il proprio id e vanno in sleep(1) prima di terminare. Il programma (thread) principale attende la terminazione dei due thread e poi stampa un messaggio e termina.

2. Provare a inviare a tali thread un argomento che verr ` a elevato al quadrato dai singoli thread. Il thread principale, infine, stamper ` a la somma dei due valori ottenuti. Fare at- tenzione, se si passa il valora per indirizzo, che la memoria ` e condivisa (il valore non deve essere modificato finch ` e il thread non ritorna il risultato!). Il valore di ritorno ` e bene che NON sia passato per indirizzo in quanto potrebbe puntare a una zona dello stack che viene eliminata al momento della terminazione del thread. Si consiglia quindi di passare i dati ‘per valore’, facendo un opportuno cast. Per evitare problemi di casting usare il tipo intptr t che ` e un intero la cui dimensione corrisponde a quella di un indirizzo.

3. Provare a “distaccare” uno dei thread e osservare l’errore restituito dalla join.

ATTENZIONE: gli errori non possono essere visualizzati con perror. Consultare il manuale delle chiamate a libreria per vedere i possibili errori restituiti.

4. Modificare il codice dei 2 thread in modo che aggiornino ripetutamente (in un ciclo for) una variabile condivisa count per un numero elevato di volte (ad esempio 1000000).

Stampare il valore finale per osservare eventuali incrementi perduti. Per evitare ottimiz-

zazioni del compilatore o dell’hardware scrivere l’aggiornamento esplicitamente usando

una variabile locale l: l=count; l++; count=l; Provare anche con count++ per vedere

eventuali differenze.

(2)

LABORATORIO SISTEMI OPERATIVI 2

6.1 Soluzioni

Ex. 1

#include <s t d l i b . h>

#include <s t d i o . h>

#include <pthread . h>

#include <s y s / s y s c a l l . h>

/ / NOTA: non funziona p e r r o r perche ’ non sono s y s c a l l ma phtread l i b r a r y c a l l s void die ( char ∗ s , i n t i ) {

p r i n t f ( ”−−> %s [% i ] \ n” , s , i ) ; e x i t ( 1 ) ;

}

void ∗ codicethread ( void ∗ i ) { pthread t t i d ;

i n t s t i d ;

t i d = p t h r e a d s e l f ( ) ; / / questo e ’ l ’ i d i n t e r n o a l l a l i b r e r i a pthread s t i d = s y s c a l l ( S Y S g e t t i d ) ; / / questo e ’ l ’ i d dato dal sistema

p r i n t f ( ”Sono i l thread %l u , (% i ) del processo %d ! \n” , t i d , s t i d , getpid ( ) ) ; sleep ( 5 ) ;

pthread exit ( NULL ) ; }

main ( ) {

pthread t th1 , th2 ; i n t r e t ;

/ / nota : se r i t o r n a un valore d i v e r s o da 0 indica un e r r o r e

i f ( r e t =pthread create(&th1 , NULL , codicethread , NULL ) <0) die ( ” e r r o r e create ” , r e t ) ; p r i n t f ( ”Creato i l thread %l u \n” , th1 ) ;

i f ( r e t =pthread create(&th2 , NULL , codicethread , NULL ) <0) die ( ” e r r o r e create ” , r e t ) ; p r i n t f ( ”Creato i l thread %l u \n” , th2 ) ;

/ / attende i due thread

i f ( r e t =pthread join ( th1 , NULL ) <0) die ( ” e r r o r e j o i n ” , r e t ) ; i f ( r e t =pthread join ( th2 , NULL ) <0) die ( ” e r r o r e j o i n ” , r e t ) ;

p r i n t f ( ”ECCOMI QUI , termino \n” ) ; }

Output:

> gcc test1.c -lpthread <=== notare l’opzione -l !!

> a.out

Creato il thread 3084999568 Creato il thread 3076606864

Sono il thread 3084999568, (13455) del processo 13454!

Sono il thread 3076606864, (13456) del processo 13454!

ECCOMI QUI, termino

>

(3)

LABORATORIO SISTEMI OPERATIVI 3

Ex. 2 NOTA: Utilizziamo il tipo intptr t che ` e un intero la cui dimensione corrisponde a quella di un indirizzo. Questo ` e utile per la portabilit ` a tra architetture 32/64-bit. (si deve includere stdint.h)

void ∗ codicethread ( void ∗ i ) { pthread t t i d ;

i n t p t r t j =( i n t p t r t ) i ; / / assegno a j i l valore passato come parametro

p r i n t f ( ”Sono i l thread %l u del processo %d ! \n” , p t h r e a d s e l f ( ) , getpid ( ) ) ; j = j ∗ j ;

sleep ( 1 ) ;

pthread exit ( ( void ∗ ) j ) ; }

main ( ) {

pthread t th [ 2 ] ; i n t p t r t v [ 2 ] = { 3 , 4 } ; i n t p t r t r [ 2 ] ; i n t r e t , i ;

/ / crea i due thread e passa v [ i ] come parametro f o r ( i =0; i <2; i ++) {

i f ( r e t =pthread create(& th [ i ] , NULL , codicethread , ( void ∗ ) v [ i ] ) <0) die ( ” e r r o r e create ” , r e t ) ;

p r i n t f ( ”Creato i l thread %l u , i n v i a t o i l valore % i \n” , th [ i ] , v [ i ] ) ; }

/ / attende i due thread e memorizza i n r [ i ] i l valore d i r i t o r n o f o r ( i =0; i <2; i ++)

i f ( r e t =pthread join ( th [ i ] , ( void ∗∗) &r [ i ] ) ) die ( ” e r r o r e j o i n ” , r e t ) ;

p r i n t f ( ”ECCOMI QUI , somma r i s u l t a t i : % i \n” , r [ 0 ] + r [ 1 ] ) ; }

Output

> a.out

Creato il thread 3085327248, inviato il valore 3 Creato il thread 3076934544, inviato il valore 4 Sono il thread 3085327248 del processo 13640!

Sono il thread 3076934544 del processo 13640!

ECCOMI QUI, somma risultati: 25

>

Ex. 3

. . .

/ / distacca i l thread th [ 0 ]

i f ( r e t =pthread detach ( th [ 0 ] ) ) die ( ” e r r o r e detach” , r e t ) ; . . .

Outuput

> a.out

Creato il thread 3084422032, inviato il valore 3 Creato il thread 3076029328, inviato il valore 4 --> errore join [22]

>

(4)

LABORATORIO SISTEMI OPERATIVI 4

Ex. 4

#include <s t d l i b . h>

#include <s t d i o . h>

#include <pthread . h>

#include <s y s / types . h>

#include <s y s / s y s c a l l . h>

# define MAX 1000000

/ / contatore globale i n t v o l a t i l e count =0;

/ / non funziona p e r r o r perche ’ non sono s y s c a l l ma phtread l i b r a r y c a l l s void die ( char ∗ s , i n t i ) {

p r i n t f ( ”−−> %s [% i ] \ n” , s , i ) ; e x i t ( 1 ) ;

}

void ∗ codicethread ( void ∗ i ) { pthread t t i d ;

i n t j , l ;

/ / somma 1 a l contatore passando da una v a r i a b i l e globale ( per aumentare l e i n t e r f e r e n z e )

/ / provare anche con count++ ( i n t e r f e r e n z e + rare ) f o r ( j =0; j <MAX; j ++) {

l =count ; l ++;

count= l ; }

pthread exit ( ( void ∗ ) count ) ; }

main ( ) {

pthread t th [ 2 ] ; i n t r e t , i ;

/ / crea i due thread f o r ( i =0; i <2; i ++) {

i f ( r e t =pthread create(& th [ i ] , NULL , codicethread , NULL ) <0) die ( ” e r r o r e create ” , r e t ) ;

p r i n t f ( ”Creato i l thread %u\n” , th [ i ] ) ; }

/ / attende i due thread f o r ( i =0; i <2; i ++)

i f ( r e t =pthread join ( th [ i ] , NULL ) ) die ( ” e r r o r e j o i n ” , r e t ) ;

p r i n t f ( ”ECCOMI QUI , contatore = % i \n” , count ) ; }

Output

> a.out

Creato il thread 3085036432 Creato il thread 3076643728 ECCOMI QUI, contatore = 1612625

> a.out

Creato il thread 3084487568 Creato il thread 3076094864 ECCOMI QUI, contatore = 1331296

> a.out

Creato il thread 3084467088

Creato il thread 3076074384

ECCOMI QUI, contatore = 1000000

Riferimenti

Documenti correlati

Il programma in C riportato in seguito usa funzioni di libreria definite nello standard POSIX (supportato da quasi tutti i sistemi UNIX) per creare più thread e mandarli in

•  Per attivare il thread deve essere chiamato il metodo start() che invoca il metodo run() (il metodo run() non può essere. chiamato direttamente, ma solo

implementazione del concetto di monitor: un oggetto java è associato ad un mutex ricorsivo tramite il quale è possibile disciplinare gli accessi da parte di diversi thread allo

 La funzione DEVE ESSERE CHIAMATA su una variabile mutex che sia già bloccata e di proprietà del thread chiamante. In tal caso la funzione pthread_mutex_unlock sblocca la

▪ Assegnare memoria e risorse per la creazione di nuovi processi è oneroso; poiché i thread condividono le risorse del processo cui appartengono, è molto più con- veniente creare

 Wait (and act) for a single thread within a large group of

• Il metodo run della classe di libreria Thread definisce l’insieme di statement Java che ogni thread (oggetto della classe) eseguirà.. concorrentemente con gli

Pthreads (Shared Memory