Indice
1 Introduzione: Il C++ non ` ancora morto e 1.1 Lo standard C++0X - C++11 . . . . . . . . . . . . . . . . . . . . . . . . 2 il C++ e le lambda 2.1 Il caso pi` semplice, le funzioni void . . . . . . . . u 2.2 Le funzioni che usano e restituiscono parametri . . 2.3 Le funzioni lambda e la visibilit` . . . . . . . . . . a 2.4 Funzioni che ricevono funzioni e funzioni anonime . 2.5 Qualche esempio funzionale ( che funziona) . . . . 3 4 4 5 5 6 7 7
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
3 Il C++ e il Multithreading 10 3.1 Allochiamo il nostro primo thread . . . . . . . . . . . . . . . . . . . . . . 10 3.2 Thread e condivisione dei dati . . . . . . . . . . . . . . . . . . . . . . . . . 12 3.3 Allocare un Thread senza creare un oggetto . . . . . . . . . . . . . . . . . 13 4 Sincronizzazione dei Thread e gestione delle risorse con i Mutex 14 4.1 I Mutex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 4.2 Mutex ed eccezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 5 Uso avanzato dei Mutex 5.1 Timed mutex e la prenotazione con timeout massimo . . . . . . . . . . . . 5.2 Accesso alle funzioni interne del mutex . . . . . . . . . . . . . . . . . . . . 5.2.1 Prenotazione multipla . . . . . . . . . . . . . . . . . . . . . . . . . 18 19 19 20
6 Il problema dei 5 loso 21 6.1 Vari approcci ingenui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 6.2 Una soluzione funzionante . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 7 Le Condition, implementazione delle code di attesa 24 7.1 Le Condition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 7.2 Ma le cose non sono cos` semplici... . . . . . . . . . . . . . . . . . . . . . . 25 1
8 Il problema del barbiere addormentato 26 8.1 Il barbiere . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 8.2 Il cliente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 8.3 Codice completo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 A Ambiente di sviluppo e problemi di A.1 GNU Gcc - g++ . . . . . . . A.1.1 MinGw . . . . . . . . A.1.2 Multithreading . . . . A.2 Microsoft Visual Studio . . . Riferimenti bibliograci v1.0.0 http://www.thedarshan.com/ VincenzoLaSpesa@gmail.com Questopera ` stata rilasciata sotto la licenza Creative Commons Attribuzione-Non e commerciale-Condividi allo stesso modo 2.5 Italia. Per leggere una copia della licenza visita il sito web http://creativecommons.org/licenses/by-nc-sa/2.5/it/ o spedisci una lettera a Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. compilazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 31 31 31 31 31
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
Il C++ ` troppo complicato! nessuno lo conosce per intero! e Il cpp non ` complicato, ` vasto. Lidea che un linguaggio vada imparato e usato e e per intero ` tipica dei linguaggi di nuova generazione come il Java, ma non ` e e assolutamente una cosa necessaria in genere. Il cpp parte dal principio che se ` possibile fare una cosa il linguaggio deve permetterlo, se poi i 4 tipi di cast o e lereditariet` multipla ti fanno orrore o paura...non usarli! Resta il fatto che siano a utili e comodi per fare workaround, e i workaround servono ( nel mondo reale almeno) e anche fare cose orribili come modicare le variabili dichiarate costanti pu` tornare utile. o un altra idea ancora pi` stupida ma comunque abbastanza in voga e che: u La libreria del C++ ` scarna! e Confondere la libreria di un linguaggio con il linguaggio ` veramente stupido! anche e dare per assunto che un linguaggio necessiti di una libreria intrinseca lo `, peraltro e le stl e la libreria standard orono un set di funzionalit` che copre tutte le necessit` a a di base, e per il resto se ne trovano a palate di librerie pronte. E adesso veniamo al vero motivo per cui sto scrivendo:
1
http://michele.sciabarra.com/page/NonUsateQuelLinguaggio
2 il C++ e le lambda
Un interessante funzione introdotta nello standard C++0X sono le lambda Le funzioni lambda sono tipiche dei linguaggi che applicano il paradigma della programmazione funzionale ( completamente o in maniera ibrida) e permettono di trattare le funzioni come se fossero oggetti, potendole quindi denire in qualunque punto del codice e assegnare a una variabile. Vediamo un esempio di come questo approccio sia stato implementato nel cpp
come si vede dal codice abbiamo denito due funzioni lambda assegnandole a variabili, adesso vediamo come comportarsi per denire funzioni che usano o producono valori (queste qui erano void > void)
la lista dei parametri in entrata viene dichiarata tra le parentesi tonde, il tipo del parametro in uscita pu` essere denito esplicitamente con > come nel caso di prodottoo o lasciato implicito come nel caso di somma e in questo caso viene dedotto dal compilatore A questo punto vi starete chiedendo a che servano le parentesi quadre suppongo
la compilazione del pezzo di codice precedente ci dar` un error: c is not captured a per renderlo visibile dobbiamo fare questo Listing 4: Il modo giusto di procedere
i nt main ( ) { i nt c ; auto somma=[&c ] ( i nt a , i nt b ) { c=a+b ; }; somma ( 2 , 2 ) ; cout << 2+2 f a << c << e n d l ; return 0 ; }
quindi passando un puntatore a this a una lambda rendiamo visibile lintero oggetto. ` addirittura possibile passare lintero contesto usando [&] e [=] dove la prima passa e per reference e la seconda per valore
altro uso molto diuso delle lambda ci permette di modicare il comportamento di un algoritmo passandogli un altro algoritmo, un semplice esempio ` una generica funzione di e ordinamento a cui passiamo una funzione di confronto, questo ci permette sia di ordinare ogetti di tipi non conosciuti dalla funzione e non ordinabili a priori sia di modicare le relazioni di ordine.
using namespace s t d ; void s o r t ( void x [ ] , i nt n , const f u n c t i o n <i nt ( void , void)>& co mpa r a to r ) { i nt i , j ; void app ; for ( i =1; i <n ; i ++) { app = x [ i ] ; j = i 1; while ( j >=0 && c o mpa r a to r ( x [ j ] , app) >0) { x [ j +1] = x [ j ] ; j ; } x [ j +1] = app ; } return ; } i nt main ( ) { s r a n d ( time ( 0 ) ) ; i nt c ; char c o s i [ ] = { p o l l o d i gomma , ammaccabanane , c o s o , c a n n u c c i a s b i r u l a } ; auto o r d i n a s t r = [ ] ( void a , void b)>i nt { return s t r l e n ( ( const char ) a) s t r l e n ( ( const char ) b ) ; }; auto d i s o r d i n a s t r = [ ] ( void a , void b)>i nt { return rand ()%6 3;}; s o r t ( ( void ) c o s i , 4 , o r d i n a s t r ) ; for ( i nt n=0;n<4;n++)co ut << c o s i [ n ] << e n d l ; cout<<endl<<e n d l ; s o r t ( ( void ) c o s i , 4 , d i s o r d i n a s t r ) ; for ( i nt n=0;n<4;n++)co ut << c o s i [ n ] << e n d l ; return 0 ; } }
3 Il C++ e il Multithreading
Unaltra funzionalit` molto interessante introdotta nel C++0X ` il supporto nativo al a e multithreading. Esistevano gi` librerie che si occupavano di multithreading in cpp ma adesso ` intea e grato nel linguaggio e nella sua libreria standard anche se il backend che eettivamente alloca i thread ` lonnipresente libreria pthread. e
10
E interessante notare che quando si chiama un thread su un oggetto, come nel caso di std::thread t1(w), non gli viene passato il vero oggetto ma una sua copia, ma di questo ne parliamo dopo. Le join servono ad aspettare che i thread niscono prima di terminare il programma,
11
infatti i thread sono concettualmente gli del processo padre ( il fatto che lo siano veramente dipende dallimplementazione) e se terminasse il processo padre i gli verrebbero terminati di conseguenza facendo generare a linux un allarmante messaggio di warning, per terminare un thread prima che abbia nito il suo lavoro si usa detach
12
using namespace s t d ; c l a s s Dummy { public : string testo ; s t r i n g nome ; void operator ( ) ( ) { for ( i nt a =0;a <15;a++){ cout<<nome << d i c e : << t e s t o << << a <<e n d l ; u s l e e p ( 1000 ( rand ( ) % 900 + 100 ) ) ; } } }; i nt main ( ) { Dummy w, w2 ; w. t e s t o=ammaccabanane ; w. nome= t h r e a d 1 ; w2=w ; w2 . nome= t h r e a d 2 ; s t d : : t h r e a d t 1 (w ) ; s t d : : t h r e a d t 2 ( s t d : : r e f (w2 ) ) ; sleep (2); w. t e s t o= Yikes ! ; w2 . t e s t o= Yikes ! ; t1 . j o i n ( ) ; t2 . j o i n ( ) ; };
Eseguendolo noterete che il comportamento del primo thread resta invariato, mentre possiamo agire sul secondo modicando i suoi dati dallesterno.
13
costituisce il main, semplicemente accodiamo i parametri da passare alla funzione e ci adiamo alle stl per la determinazione corretta del tipo 2 Listing 9: E se volessi passare parametri alla procedura e magari non usare un oggetto?
#include #include #include #include <i o s t r e a m > <thr ea d> <c s t d l i b > <s t r i n g >
using namespace s t d ; void stampa ( s t r i n g co sa , s t r i n g a l t r a c o s a ) { for ( i nt a =0;a <10;a++){ cout<< c o s a << a l t r a c o s a << e n d l ; sleep (1); } } i nt main ( ) { s t d : : t h r e a d t 1 ( stampa , b l a b l a b l a , yada yada yada ) ; t1 . j o i n ( ) ; }; };
14
Per prima cosa cerchiamo di denire cosa deve succedere su una sezione critica: una volta individuata e minimizzata una sezione critica dobbiamo fare in modo che 1. sia vericata la mutua esclusione ossia che soltanto un processo per volta possa trovarsi nella sezione critica 2. si eviti lattesa indenita da parte di un processo che tenta di accedere a una sezione critica occupata 3. un processo che si trova fuori dalla sezione critica non deve poter interferire con laccesso alla sezione critica dei processi in attesa
4.1 I Mutex
Lo strumento fondamentale per la sincronizzazione oerto dalle stl ` il Mutex, che ` e e la crasi di mutual exlusion e serve appunto ad evitare che pi` processi del necessario u possano accedere ad una sezione critica. Esistono 4 tipi di mutex: 1. semplice ( std::mutex ) 2. semplice con timeout ( std::timed mutex ) 3. ricorsivo ( std::recursive mutex ) 4. ricorsivo con timeout ( std::recursive timed mutex ) un mutex ` semplice se il suo stato ` binario ( libero/occupato ) e e ` invece ricorsivo se permette pi` accessi prima di essere occupato e u un mutex ` timed se ` possibile fare in modo che si liberi da solo dopo un certo e e tempo fondamentalmente un mutex dispone di almeno 3 funzioni: void lock(); che permette di occuparlo o di attenderlo se ` gi` occupato e a void unlock(); che permette di liberarlo bool try lock(); che permette occuparlo se ` possibile senza per` rimanere in attesa e o vediamo come usarli, per prima cosa costruiamo un programma che necessiti di essere sincronizzato
15
using namespace s t d ; void stampa ( s t r i n g t e s t o ) { for ( i nt a =0;a<t e s t o . l e n g t h ( ) ; a++){ cout << t e s t o [ a ] ; f l u s h ( co ut ) ; u s l e e p ( 100 ( rand ( ) % 900 + 100 ) ) ; } cout << e n d l ; } c l a s s Worker { public : string testo ; Worker ( s t r i n g t ) { t e s t o=t ; } void operator ( ) ( ) { stampa ( t e s t o ) ; } }; i nt main ( ) { t h r e a d t 1 ( Worker ( Quanto l e g n o r o d e r e b b e un r o d i t o r e s e un r o d i t o r e p o t e s s e r o d e r e i l l e g n o ? ) ) ; t h r e a d t 2 ( Worker ( How much wood c o u l d a woodchuck chuck i f a woodchuck c o u l d chuck wood? ) ) ; t1 . j o i n ( ) ; t2 . j o i n ( ) ; };
il codice ci far` ottenere qualcosa del tipo: a QHowu anmtuoc hl egwonodo rcooudelrd ebbae wuoond rocdhiutcokr cehuc ske uinf a r odiwtooroed chpuoctkes csouled rchoduecrek i l woloegdno??
16
La sincronizzazione si eettua creando un mutex globale e condividendolo tra i thread che vanno sincronizzati e racchiudendo la sezione critica dentro una lock e una unlock Listing 11: La versione sincronizzata del codice precedente
... c l a s s Worker { public : string testo ; mutex m; Worker ( s t r i n g t , mutex mtx ) { m =mtx ; t e s t o=t ; } void operator ( ) ( ) { m >l o c k ( ) ; stampa ( t e s t o ) ; m >u n l o c k ( ) ; } }; i nt main ( ) { mutex m new mutex ( ) ; = t h r e a d t 1 ( Worker ( Quanto l e g n o r o d e r e b b e un r o d i t o r e s e un r o d i t o r e p o t e s s e r o d e r e i l l e g n o ? ,m) ) ; t h r e a d t 2 ( Worker ( How much wood c o u l d a woodchuck chuck i f a woodchuck c o u l d chuck wood? ,m) ) ; t1 . j o i n ( ) ; t2 . j o i n ( ) ; };
17
Un modo pi` compatto di usare in maniera sicura i mutex si pu` ottenere usando u o gli ogetti lock guard delle stl, che permettono anche di rilasciare il mutex in maniera automatica quando si esce dal blocco in cui sono denite ( lo sbloccano nel loro distruttore per essere precisi), il codice precedente si pu` riscrivere in questo modo: o Listing 13: Uso di una guard
void operator ( ) ( ) { l o c k g u a r d <mutex> l o c k ( m) ; stampa ( t e s t o ) ; }
Precisiamo una cosa per`... o Il fatto che la guard blocchi il mutex non implica che lintero programma non venga terminato...infatti dopo aver sbloccato il mutex propaga leccezione generata a livello superiore e se non c` un catch a livello superiore questo equivale alla e terminazione del processo padre Quindi se ci limitiamo a guardare questi snippet lesempio con la gestione manuale funziona meglio di quello con la lock ma nel caso generale luso della lock ` comodo e perch ci permette di scrivere codici per la gestione delle eccezioni che non tengono e conto del mutex.
18
unique lock o u Con unique lock un mutex pu` fare molto di pi` di quello che permette la lock guard Si pu` cercare di prenotarlo in maniera non bloccante ( se ` libero lo si occupa, o e se non ` libero non si attende) e Si pu` cercare di prenotarlo fornendo un timeout massimo di attesa ( se si o tratta di un timed mutex ovviamente) Si pu` accedere direttamente alle funzioni del mutex o e un sacco di altre cose per le quali vi rimando a una reference
3
Questa funzione prova ad accedere al mutex aspettando massimo 5 millisecondi, il valore della lock si usa per determinare se laccesso ` avvenuto o no e
19
5.2.1
Prenotazione multipla
Un problema molto comune nella programmazione concorrente ` la necessita da parte e di un processo di accedere in maniera esclusiva a pi` risorse, ` un problema che se u e gestito male pu` causare facilmente deadlock o starvation in quanto se un processo che o ha acquisito parte delle risorse necessarie attende altre risorse per continuare e queste risorse sono bloccate da altri processi anche loro in attesa tutti i processi restano bloccati in attesa luno dellaltro, in questo caso le stl ci vengono in aiuto dandoci un costrutto che permette di bloccare n mutex restando in attesa ma non bloccandoli Listing 17: Prenotazione multipla
void p r e n o t a ( s t d : : mutex a , s t d : : mutex a ) { s t d : : u n i q u e l o c k <s t d : : mutex> l o c k a ( a , s t d : : d e f e r l o c k ) ; s t d : : u n i q u e l o c k <s t d : : mutex> l o c k b ( b , s t d : : d e f e r l o c k ) ; std : : lock ( lock a , lock b ) ; // f a i q u a l c o s a d i c r i t i c o }
20
21
Partendo da questo modello possiamo cominciare a cercare una soluzione, quella pi` u immediata potrebbe esere: un losofo prende la bacchetta a destra, poi quella a sinistra e poi mangia. ma cosa succede se tutti prendono contemporaneamente la forchetta di destra? un deadlock, muoiono di fame aspettando che qualcuno liberi qualcosa ma nessuno liberer` a mai niente. unaltra soluzione potrebbe essere: Un losofo di numero pari prende prima la forchetta di destra e poi quella di sinistra, un losofo dispari il contrario Ma questo ` barare,scartiamola e Ci rendiamo conto che un losofo deve rilasciare la bacchetta se non pu` prendere la o seconda, qualcosa del tipo Un losofo prende la bacchetta di destra, poi cerca di prendere quella di sinistra (trylock) e se non pu` le posa entrambe e riprova in seguito o ma che succede se i loso partono insieme? lalgoritmo va in loop: tutti prendono quella di destra, nessuno pu` prendere quella a sinistra, tutti posano tutto e si ricomincia, o le operazioni necessitano di essere eseguite in maniera atomica
Se siete interessati alla versione originale del problema di Dijkstra ,risolta interamente con i semafori, potete dare un occhiata a questo testo su google docs http://goo.gl/96ZaX , se poi avete anche interessi archeologici c` la scansione della versione originale dattiloscritta qui e http://www.cs.utexas.edu/~ EWD/ewd03xx/EWD310.PDF
22
}; ...
23
using namespace s t d ; c l a s s Worker { public : i nt numero ; s t d : : c o n d i t i o n v a r i a b l e coda ; mutex m; Worker ( i nt n , s t d : : c o n d i t i o n v a r i a b l e cond , mutex mtx ) { coda=cond ; numero=n ; m =mtx ; }
24
};
void operator ( ) ( ) { cout << Thread << numero << a l l o c a t o , mi metto i n coda << e n d l ; s t d : : u n i q u e l o c k <s t d : : mutex> l k ( m) ; coda>wa it ( l k ) ; cout << Thread << numero << r i s v e g l i a t o d a l l a coda << e n d l ; }
i nt main ( ) { s t d : : c o n d i t i o n v a r i a b l e coda= new c o n d i t i o n v a r i a b l e ( ) ; mutex m new mutex ( ) ; = i nt a ; std : : thread threads [ 1 0 ] ; for ( a =0;a <10;a++){// c r e o t h r e a d s [ a ]= new s t d : : t h r e a d ( Worker ( a +1 , coda ,m) ) ; u s l e e p ( 100000 ) ; } for ( a =0;a <10;a++){// s v e g l i o u s l e e p ( 1000 ( rand ( ) % 9 0 0 ) ) ; coda>n o t i f y o n e ( ) ; } for ( a =0;a <10;a++)// a s p e t t o t e r m i n e { t h r e a d s [ a]> j o i n ( ) ; delete ( t h r e a d s [ a ] ) ; }
};
25
8.1 Il barbiere
1. Controlla se ci sono clienti in attesa (attraverso i metodi del Monitor) 2. se non ce ne sono si addormenta ( svegliandosi al punto 3) 3. se ce ne sono li rade e torna al punto 1 la rasatura consiste in: liberare un Cliente dalla coda della sala di attesa (attesa.notify one) , il cliente liberato occupa la coda della poltrona radere il Cliente, liberarlo dalla coda della poltrona (poltrona.notify one())
8.2 Il cliente
1. Entra nella sala, cerca di sedersi (a) Se pu` sedersi: o i. Se ` lunica persona seduta sveglia il barbiere (letto.notify one()) e ii. va al punto 2 (b) Se non pu` sedersi esce dalla sala e va al punto 5 o 26
2. Si mette in attesa nella coda della sala (attesa.wait(lk)) 3. una volta svegliato occupa il barbiere (barbiere > lock()) e si mette in attesa sulla sedia della poltrona (poltrona.wait(barbiere)). il mutex sul barbiere evita il problema di una possibile signal non voluta ( vedi sopra il paragrafo 7.2) una volta svegliato libera il barbiere ed esce dalla sala 4. va in giro a bighellonare e poi torna al punto 1 In questa implementazione sono possibili delle signal superue su un barbiere gi` a sveglio, ma sono irrilevanti
using namespace s t d ; i nt dormi ( f l o a t base , f l o a t v a r i a b i l e ) { i nt k =10001000; i nt b a s e i =( i nt ) ba se k ; i nt v a r i a b i l e i =0; i f ( v a r i a b i l e >0) v a r i a b i l e i=rand ( ) % ( i nt ) ( v a r i a b i l e k ) ; u s l e e p ( b a s e i+v a r i a b i l e i ) ; return b a s e i+v a r i a b i l e i ; }; c l a s s Sta nza { private : i nt o c c u p a t e ; s t d : : mutex monitor m ; public : std : : c o n d i t i o n v a r i a b l e attesa ; std std std std i nt : : mutex a t t e s a m ; : : c o n d i t i o n v a r i a b l e poltrona ; : : condition variable letto ; : : mutex b a r b i e r e ; sedie ;
27
i nt p r e n o t a ( ) { s t d : : u n i q u e l o c k <s t d : : mutex> l k ( monitor m ) ; i f ( o ccupa te>=s e d i e ) return 1; o c c u p a t e++; cout << o c c u p a t e << s e d i e o c c u p a t e <<e n d l ; return o c c u p a t e ; } i nt guarda ( ) { s t d : : u n i q u e l o c k <s t d : : mutex> l k ( monitor m ) ; return o c c u p a t e ; } i nt l i b e r a ( ) { s t d : : u n i q u e l o c k <s t d : : mutex> l k ( monitor m ) ; o ccupa te ; cout << o c c u p a t e << s e d i e o c c u p a t e <<e n d l ; return o c c u p a t e ; } Sta nza ( i nt n s e d i e ) { this >s e d i e=n s e d i e ; o c c u p a t e =0; }
};
i nt numero ; i nt a z i o n i ; Sta nza s t a n z a ; s t d : : u n i q u e l o c k <s t d : : mutex> b a r b i e r e ; B a r b i e r e ( Sta nza s t ) { a z i o n i =0; this >s t a n z a=s t ; b a r b i e r e= new s t d : : u n i q u e l o c k <s t d : : mutex>( sta nza >b a r b i e r e , s t d : : d e f e r l o c k t ( ) ) } void operator ( ) ( ) {
28
while ( true ) { cout << B a r b i e r e c o n t r o l l a s e c i sono c l i e n t i i n a t t e s a <<e n d l ; i f ( sta nza >guarda ()==0) { cout << B a r b i e r e s i addormenta<<e n d l ; s t d : : u n i q u e l o c k <s t d : : mutex> l k ( sta nza >b a r b i e r e ) ; stanza >l e t t o . wa it ( l k ) ; } cout << ++a z i o n i << B a r b i e r e s e r v e un c l i e n t e <<e n d l ; stanza >a t t e s a . n o t i f y o n e ( ) ; dormi ( 2 , 2 ) ; stanza >p o l t r o n a . n o t i f y o n e ( ) ;
};
i nt numero ; Sta nza s t a n z a ; s t d : : u n i q u e l o c k <s t d : : mutex> b a r b i e r e ; C l i e n t e ( Sta nza s t , i nt n ) { s t a n z a=s t ; numero=n ; b a r b i e r e= new s t d : : u n i q u e l o c k <s t d : : mutex>( sta nza >b a r b i e r e , s t d : : d e f e r l o c k t ( ) ) } void work ( ) { cout << Thread << numero << a l l o c a t o , e n t r a d a l b a r b i e r e << e n d l ; i nt s=sta nza >p r e n o t a ( ) ; i f ( s <0) { cout << Thread << numero << t u t t e l e s e d i e sono o ccupa te , e s c e << e n d l ; return ; } else { i f ( s >0) { cout << Thread<< numero << s i s i e d e e a s p e t t a << e n d l ; i f ( s==1)
29
{ cout << Thread << numero << s v e g l i a i l b a r b i e r e << e n d l ; dormi ( 1 , 0 ) ; stanza >l e t t o . n o t i f y o n e ( ) ;
} s t d : : u n i q u e l o c k <s t d : : mutex> l k ( sta nza >a t t e s a m ) ; stanza >a t t e s a . wa it ( l k ) ; cout << Thread<< numero << s i a l z a << e n d l ; stanza >l i b e r a ( ) ;
b a r b i e r e >l o c k ( ) ; cout << Thread << numero << s i s i e t e e s i f a r a s a r e << e n d l ; stanza >p o l t r o n a . wa it ( b a r b i e r e ) ; b a r b i e r e >u n l o c k ( ) ; cout << Thread << numero << e s c e << e n d l ; } } void operator ( ) ( ) { for ( i nt a =0; a <2; a++) { work ( ) ; cout << Thread << numero << va i n g i r o a b i g h e l l o n a r e << e n d l ; dormi ( 3 0 , 3 0 ) ; } cout << Thread << numero << muore << e n d l ; }
};
i nt main ( i nt a r g c , char a r g v ) { Sta nza s t a n z a ( 5 ) ; i nt a ; std : : thread threads [ 1 5 ] ; s t d : : t h r e a d b a r b i e r e=new s t d : : t h r e a d ( B a r b i e r e (& s t a n z a ) ) ; for ( a =0; a <15; a++) // c r e o { dormi ( 0 , a ) ; t h r e a d s [ a ]= new s t d : : t h r e a d ( C l i e n t e (& sta nza , a + 1 ) ) ; } for ( a =0; a <15; a++) // a s p e t t o t e r m i n e { t h r e a d s [ a]> j o i n ( ) ; delete ( t h r e a d s [ a ] ) ;
30
};
E possibile compilare parte dei sorgenti usando MinGw6 che ` un porting windows di e gcc, il supporto di compilazione ` completo mentre non lo ` il supporto alle librerie, in e e particolare quelle riguardanti i thread visto che i pthread non hanno un corrispettivo windows ( non open source quantomeno7 ) A.1.2 Multithreading
Il supporto ai thread della stl usa la libreria pthread per creare e gestire i thread, per attivarla ci si serve del ag -lpthread ed ` necessario che gcc includa gcc-multilib e (disponibile come pacchetto in molte distribuzioni di linux) se non funziona e in particolare se da errori del tipo fatal error: asm/errno.h bisogna applicare una patch alla libreria andate su /usr/include/ e controllate che esista la cartella asm-generic, se esiste fatene un link software su /usr/include/asm (NON rinominatela, non si sa mai che pu` o succedere con un aggiornamento di pacchetti ). Questo dovrebbe risolvere il problema, e possibilmente mentre sto scrivendo non ` pi` una cosa necessaria. e u
31
Riferimenti bibliograci
[1] http://www.thedarshan.com/informatica/2011/02/il-c-non-e-ancora-morto/ [2] http://www.thedarshan.com/informatica/2011/03/il-cp-e-le-lambda-c0x/ [3] http://www.thedarshan.com/informatica/2011/10/il-c-e-il-multithreading-c0x/ [4] http://www.thedarshan.com/informatica/2011/10/sincronizzazione-dei-thread-egestione-delle-risorse-con-i-mutex-c0x/ [5] http://www.thedarshan.com/informatica/2011/11/uso-avanzato-dei-mutex-i-5loso-c0x/ [6] http://www.thedarshan.com/informatica/2011/11/le-condition-implementazionedelle-code-di-attesa-il-problema-del-barbiere-addormentato-c0x/
32