Gentoo Archives: gentoo-commits

From: "Davide Cendron (scen)" <scen@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo commit in xml/htdocs/doc/it/articles: l-posix2-it.xml
Date: Thu, 01 May 2008 14:50:10
Message-Id: E1Jra6p-0002sd-0b@stork.gentoo.org
1 scen 08/05/01 14:50:07
2
3 Added: l-posix2-it.xml
4 Log:
5 Initial commit: version 1.2, revision 1.4 of EN CVS
6
7 Revision Changes Path
8 1.1 xml/htdocs/doc/it/articles/l-posix2-it.xml
9
10 file : http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/it/articles/l-posix2-it.xml?rev=1.1&view=markup
11 plain: http://sources.gentoo.org/viewcvs.py/gentoo/xml/htdocs/doc/it/articles/l-posix2-it.xml?rev=1.1&content-type=text/plain
12
13 Index: l-posix2-it.xml
14 ===================================================================
15 <?xml version='1.0' encoding="UTF-8"?>
16 <!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/it/articles/l-posix2-it.xml,v 1.1 2008/05/01 14:50:06 scen Exp $ -->
17 <!DOCTYPE guide SYSTEM "/dtd/guide.dtd">
18
19 <guide link="/doc/it/articles/l-posix2.xml" disclaimer="articles" lang="it">
20 <title>Spiegazioni sui thread POSIX, parte 2</title>
21
22 <author title="Autore">
23 <mail link="drobbins@g.o">Daniel Robbins</mail>
24 </author>
25 <author title="Traduzione">
26 <mail link="zanetti.massimo@×××××.com">Massimo Zanetti</mail>
27 </author>
28
29 <abstract>
30 I thread POSIX sono un ottima modo per incrementare la reattività e le
31 prestazioni del vostro codice. In questo articolo, il secondo di una serie di
32 tre, Daniel Robbins vi mostra come proteggere l'integrità delle strutture di
33 dati condivise nel vostro codice con thread usando delle eccellenti piccole cose
34 chiamate mutex.
35 </abstract>
36
37 <!-- La versione originale di questo articolo è stata pubblicata su IBM
38 developerWorks, ed è di proprietà della Westtech Information Services. Questo
39 documento è una versione aggiornata dell'articolo originale, e contiene diversi
40 miglioramenti fatti dal Gentoo Linux Documentation Team
41 -->
42
43 <version>1.2</version>
44 <date>2005-10-09</date>
45
46 <chapter>
47 <title>Le piccole cose chiamate mutex</title>
48 <section id="thread3c">
49 <title>Mutex me!</title>
50 <body>
51
52 <p>
53 Nel mio <uri link="/doc/it/articles/l-posix1.xml">precedente articolo</uri>, ho
54 parlato del codice con thread che faceva cose inusuali ed inaspettate. Due
55 thread che incrementano una variabile globale venti volte. La variabile avrebbe
56 dovuto avere un valore finale di 40, ma invece terminava con un valore di 21.
57 Che cos'era successo? Il problema si è verificato perché un thread "cancellava"
58 ripetutamente l'incremento fatto dall'altro. Diamo un'occhiata a del codice
59 corretto che usa un <b>mutex</b> per risolvere il problema:
60 </p>
61
62 <pre caption="thread3.c">
63 #include &lt;pthread.h&gt;
64 #include &lt;stdlib.h&gt;
65 #include &lt;unistd.h&gt;
66 #include &lt;stdio.h&gt;
67
68 int myglobal;
69 pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER;
70
71 void *thread_function(void *arg) {
72 int i,j;
73 for ( i=0; i&lt;20; i++ ) {
74 pthread_mutex_lock(&amp;mymutex);
75 j=myglobal;
76 j=j+1;
77 printf(".");
78 fflush(stdout);
79 sleep(1);
80 myglobal=j;
81 pthread_mutex_unlock(&amp;mymutex);
82 }
83 return NULL;
84 }
85
86 int main(void) {
87
88 pthread_t mythread;
89 int i;
90
91 if ( pthread_create( &amp;mythread, NULL, thread_function, NULL) ) {
92 printf("error creating thread.");
93 bort();
94 }
95
96 for ( i=0; i&lt;20; i++) {
97 pthread_mutex_lock(&amp;mymutex);
98 myglobal=myglobal+1;
99 pthread_mutex_unlock(&amp;mymutex);
100 printf("o");
101 fflush(stdout);
102 sleep(1);
103 }
104
105 if ( pthread_join ( mythread, NULL ) ) {
106 printf("error joining thread.");
107 abort();
108 }
109
110 printf("\nmyglobal equals %d\n",myglobal);
111
112 exit(0);
113
114 }
115 </pre>
116
117 </body>
118 </section>
119 <section>
120 <title>Tempo di capire</title>
121 <body>
122
123 <p>
124 Se paragonate questo codice con la versione del mio <uri
125 link="/doc/it/articles/l-posix1.xml">precedente articolo</uri>, noterete
126 l'aggiunta delle chiamate a pthread_mutex_lock() e pthread_mutex_unlock().
127 Queste chiamate compiono una funzione fondamentale nei programmi con thread.
128 Forniscono un metodo di mutua esclusione (da cui il nome). Due thread non
129 possono avere lo stesso mutex bloccato nello stesso momento.
130 </p>
131
132 <p>
133 I mutex lavorano così. Se il thread "a" prova a bloccare un mutex mentre il
134 thread "b" ha lo stesso mutex bloccato, il thread "a" va in sleep. Appena il
135 thread "b" rilascia il mutex (grazie ad una chiamata a pthread_mutex_unlock()),
136 il thread "a" riuscirà a bloccare il mutex (in altre parole ritornerà dalla
137 chiamata a pthread_mutex_lock() con il mutex bloccato). Allo stesso modo se il
138 thread "c" prova a bloccare il mutex mentre il thread "a" lo sta tenendo,
139 anche il thread "c" andrà temporaneamente in sleep. Tutti i thread che vanno in
140 sleep, avendo chiamato pthread_mutex_lock() su di un mutex già bloccato si
141 mettono in coda per l'accesso a quel mutex.
142 </p>
143
144 <p>
145 pthread_mutex_lock() e pthread_mutex_unlock() sono usati di norma per proteggere
146 strutture di dati. Cioè, siete sicuri che solo un thread alla volta possa
147 accedere ad una certa struttura dati bloccandola e sbloccandola. Come potete
148 aver già indovinato, la libreria POSIX dei thread garantisce un blocco senza
149 dover mettere il thread in sleep se un thread prova a bloccare un mutex
150 sbloccato.
151 </p>
152
153 <figure link="/images/docs/l-posix-mutex.gif" caption="Per il vostro piacere, 4
154 znurts rimettono in atto una scena da recenti chiamate pthread_mutex_lock()"/>
155
156 <p>
157 Il thread in questa immagine che ha il mutex bloccato può accedere alla
158 complessa struttura dati senza doversi preoccupare di avere altri thread che
159 ci provino allo stesso tempo. La struttura dati è effettivamente "congelata"
160 fino a che il mutex non viene sbloccato. È come se le chiamate a
161 pthread_mutex_lock() e pthread_mutex_unlock() fossero cartelli di "lavori in
162 corso" che delimitano una particolare parte dei dati condivisi che è stata
163 modificata o letta. Le chiamate si comportano come avvisi per gli altri thread
164 per mandarli in sleep e aspettare il loro turno per bloccare il mutex.
165 Ovviamente questo è vero se si delimita ciascuna "read" e "write" ad una
166 particolare struttura dati con chiamate a pthread_mutex_lock() e
167 pthread_mutex_unlock().
168 </p>
169
170 </body>
171 </section>
172 <section>
173 <title>Ma perché i mutex?</title>
174 <body>
175
176 <p>
177 Sembra interessante, ma perché vogliamo mettere i nostri thread in sleep? Dopo
178 tutto, il principale pregio dei thread non è proprio la loro abilità nel
179 lavorare indipendentemente ed in molti casi contemporaneamente? Certo, questo è
180 assolutamente vero. Tuttavia, ciascun programma con thread non banali richiede
181 almeno un certo uso dei mutex.un po' di uso dei mutex. Rivediamo il nostro
182 programma dell'esempio per capire perché. Se date un'occhiata a
183 thread_function(), noterete che il mutex è bloccato all'inizio del ciclo e
184 rilasciato alla fine. In questo esempio, mymutex è usato per proteggere il
185 valore di myglobal.
186 </p>
187
188 <p>
189 Se guardate attentamente thread_function(), noterete che il codice relativo
190 all'incremento copia myglobal su di una variabile locale, incrementa la
191 variabile locale, va in sleep per un secondo, e solo allora copia il valore
192 della variabile locale su myglobal. Senza il mutex
193 thread_function()sovrascriverebbe il valore incrementato quando si sveglia, se
194 il nostro thread principale incrementa myglobal durante il breve sonno di un
195 secondo di thread_function(). Usare un mutex assicura che questo non succeda
196 (Nel caso voi vi stiate chiedendo, ho aggiunto il ritardo di un secondo per
197 mostrare un risultato difettoso. Non c'è nessuna motivo perché thread_function()
198 vada in sleep per un secondo prima di riscrivere il valore della variabile
199 locale su myglobal). Il nostro nuovo programma usando il mutex produce l'effetto
200 desiderato.
201 </p>
202
203 <pre caption="Output del programma che usa il mutex">
204 $ <i>./thread3</i>
205 o..o..o.o..o..o.o.o.o.o..o..o..o.ooooooo
206 myglobal vale 40
207 </pre>
208
209 <p>
210 Per esplorare ulteriormente questo concetto estremamente importante, diamo
211 un'occhiata alla parte di codice del nostro programma che esegue l'incremento:
212 </p>
213
214 <pre caption="Codice per l'incremento">
215 thread_function() increment code:
216 j=myglobal;
217 j=j+1;
218 printf(".");
219 fflush(stdout);
220 sleep(1);
221 myglobal=j;
222
223 main thread increment code:
224 myglobal=myglobal+1;
225 </pre>
226
227 <p>
228 Se questo codice fosse in un programma a singolo thread ci si aspetterebbe che
229 il codice thread_function() fosse completamente eseguita. L'esecuzione verrebbe
230 allora seguita dal codice principale del thread (o nella maniera inversa). In un
231 programma con thread ma senza mutex, il codice può (e spesso lo farà, grazie
232 alla chiamata a sleep()) finire l'esecuzione in quest'ordine:
233 </p>
234
235 <pre caption="Ordine di esecuzione">
236 thread_function() thread main thread
237
238 j=myglobal;
239 j=j+1;
240 printf(".");
241 fflush(stdout);
242 sleep(1); myglobal=myglobal+1;
243 myglobal=j;
244 </pre>
245
246 <p>
247 Quando il codice viene eseguito in questo particolare ordine la modifica fatta
248 dal thread principale alla variabile myglobal viene sovrascritta. In questo modo
249 finiamo con un valore non corretto alla fine del nostro programma. Se stessimo
250 manipolando dei puntatori probabilmente finiremmo con un segfault. Notate che il
251 nostro thread di thread_function() esegue tutte le sue istruzioni in ordine. Non
252 è come se thread_function() facesse qualche cosa non in ordine. Il problema è
253 che abbiamo un altro thread che sta facendo altre modifiche alla stessa
254 struttura dati nello stesso tempo.
255 </p>
256
257 </body>
258 </section>
259 <section>
260 <title>Dentro i thread 1</title>
261 <body>
262
263 <p>
264 Prima che vi spieghi come trovare il modo di usare i mutex, vi offro un piccolo
265 sguardo del lavoro interno dei thread. Ecco il nostro primo esempio:
266 </p>
267
268 <p>
269 Diciamo che voi abbiate un thread principale che crea tre nuovi thread: i thread
270 "a", "b" e "c". Decidiamo che il thread "a" sia stato creato per primo, il
271 thread "b" per secondo e il thread "c" per ultimo.
272 </p>
273
274 <pre caption="Ordine di creazione dei thread">
275 pthread_create( &amp;thread_a, NULL, thread_function, NULL);
276 pthread_create( &amp;thread_b, NULL, thread_function, NULL);
277 pthread_create( &amp;thread_c, NULL, thread_function, NULL);
278 </pre>
279
280 <p>
281 Dopo che la prima chiamata a pthread_create() è completata, voi potete
282 immaginare che, o il thread "a" esiste o, che ha finito e che è ora fermo. Dopo
283 la seconda chiamata a pthread_create(), sia il thread principale che il thread
284 "b" possono pensare che il thread "a" esista ( o sia fermo).
285 </p>
286
287 <p>
288 Tuttavia, immediatamente dopo che la seconda chiamata a create() ritorna, il
289 thread principale non può immaginare quale thread (a o b) stia per partire per
290 primo. Benché ambedue i thread esistano è a discrezione del kernel e della
291 libreria dei thread dargli un intervallo di tempo di CPU. Non c'è una regola
292 fissa su chi parta per primo. Ora è molto probabile che il thread "a" incominci
293 l'esecuzione prima del thread "b", ma non è garantito. Questo è specialmente
294 vero su macchine multi-processore. Se voi scrivete del codice che assuma che il
295 thread "a" effettivamente incominci la sua esecuzione prima del thread "b", vi
296 ritroverete con un programma che funzionerà il 99% delle volte. O peggio, un
297 programma che funziona il 100% delle volte sulla vostra macchina ma mai ( 0%)
298 sul server a quattro processori del vostro cliente.
299 </p>
300
301 <p>
302 Un'altra cosa che possiamo imparare da questo esempio è che la libreria dei
303 thread conserva l'ordine di esecuzione del codice per ciascun thread
304 individuale. In altre parole, queste tre chiamate a pthread_create() verranno
305 eseguite nell'ordine in cui compaiono. Dal punto di vista del thread principale,
306 tutto il codice sta lavorando secondo ordine. Qualche volta possiamo sfruttare
307 questo per ottimizzare parte dei nostri programmi con thread. Come nell'esempio
308 sopra il thread "c" può pensare che i thread "a" e "b" stiano girando o abbiano
309 già terminato. Non ci si deve preoccupare della possibilità che i thread "a"
310 o "b" non siano ancora stati creati. Potete usare questa logica per ottimizare
311 i vostri programmi con i thread.
312 </p>
313
314 </body>
315 </section>
316 <section>
317 <title>Dentro i thread 2</title>
318 <body>
319
320 <p>
321 OK, adesso come altro ipotetico esempio, supponiamo di avere un po' di thread
322 che stanno eseguendo il codice qui sotto:
323 </p>
324
325 <pre caption="Codice in esecuzione">
326 myglobal=myglobal+1;
327 </pre>
328
329 <p>
330 Abbiamo bisogno di bloccare/sbloccare il mutex rispettivamente prima e dopo
331 l'incremento? Alcuni di voi potrebbe dire di no. Il compilatore, dopo tutto,
332 molto probabilmente compilerà l'assegnazione sopra in un unica istruzione
333 macchina. Come sapete una singola istruzione macchina non può essere interrotta
334 "mid-stream". Anche gli interrupt hardware rispettano l'atomicità delle
335 istruzioni macchina. A causa di questa tendenza si può essere tentati di
336 lasciare fuori le chiamate pthread_mutex_lock() e pthread_mutex_unlock(). Non
337 fatelo.
338 </p>
339
340 <p>
341 Sono stato un debole? Non proprio. Primo non dovreste presumere che
342 l'assegnamento sopra sarà compilato come una singola istruzione macchina, a meno
343 che non lo abbiate verificato di persona. Anche se inserite alcune parti scritte
344 in assembler per essere sicuri che l'incremento avvenga atomicamente o anche se
345 scrivete il compilatore da voi, potete ancora avere dei problemi.
346 </p>
347
348 <p>
349 Ecco perché. Usare una singola inline assembler opcode probabilmente funzionerà
350 magnificamente su di una macchina con un unico processore. Ciascun incremento
351 avviene atomicamente ed è probabile che il risultato sarà quello desiderato. Ma
352 su di una macchina multiprocessore è un'altra storia. Con le macchine con più
353 CPU potete avere due processori distinti che eseguono la assegnazione sopra
354 quasi (o esattamente) allo stesso tempo. E ricordatevi anche che questa modifica
355 della memoria ha bisogno di passare dalla cache L1 alla L2 e poi alla memoria
356 principale. (Una macchina SMP non è solo un processore addizionale; ha anche
357 bisogno di hardware speciale per arbitrare l'accesso alla RAM). Alla fine, voi
358 non avete idea di quale CPU vinca la "gara" per scrivere nella memoria
359 principale. Per produrre codice prevedibile, voi volete usare i mutex. I mutex
360 inseriscono una "memory barrier", che assicura che le scritture nella memoria
361 principale avvengano nell'ordine in cui i thread bloccano i mutex.
362 </p>
363
364 <p>
365 Considerate una architettura SMP che aggiorni la memoria principale in blocchi
366 da 32-bit. Se state incrementando un intero a 64-bit senza i mutex, i quattro
367 byte più significativi possono provenire da una CPU e gli altri quattro da
368 un'altra. Male! Peggio ancora, usando questa tecnica scadente, il vostro
369 programma fallirà una volta ad ogni morte di papa o anche alle tre di mattina
370 sul sistema di un vostro importante cliente. David R. Butenhof, nel suo libro,
371 Programming with POSIX Threads (vedi <uri link="#resources">Risorse</uri> alla
372 fine dell'articolo), contempla tutte le permutazioni possibili quando non si
373 usano i mutex.
374 </p>
375
376 </body>
377 </section>
378 <section>
379 <title>Troppi mutex</title>
380 <body>
381
382 <p>
383 Se usate troppi mutex, il vostro codice non avrà nessun tipo di concorrenza
384 e girerà più lentamente di uno con una soluzione single-threaded. Se ne mettete
385 troppo pochi, il vostro codice avrà bug strani ed imbarazzanti. Fortunatamente
386 c'è una via di mezzo. Prima di tutto i mutex sono usati per rendere seriale
387 l'accesso a dati condivisi. Non usateli per dati non condivisi e neanche se la
388 logica del vostro programma assicura che solo un thread abbia accesso ad una
389 certa struttura dati in un determinato tempo.
390 </p>
391
392 <p>
393 In secondo luogo se state usando dati condivisi, usate i mutex sia in lettura
394 che in scrittura. Circondate le vostre sezioni di lettura e scrittura con
395 pthread_mutex_lock() e pthread_mutex_unlock(), o usatele ogni volta che un
396 invariante del programma è momentaneamente rotto. Imparate a vedere il vostro
397 codice secondo la prospettiva di un singolo thread e assicuratevi che ciascun
398 thread nel vostro programma abbia una buona visione della memoria. Probabilmente
399 impiegherete molto tempo prima di abituarvi a scrivere del codice con i mutex,
400 ma presto diventeranno una seconda natura per voi e sarete capaci di usarli in
401 modo corretto senza doverci pensare <e>troppo</e>.
402 </p>
403
404 </body>
405 </section>
406 <section>
407 <title>Usare le chiamate: inizializzazione</title>
408 <body>
409
410 <p>
411 OK, adesso è giunto il momento di vedere tutti i possibili utilizzi dei mutex.
412 Primo: incominciamo con l'inizializzazione. Nel nostro <uri
413 link="#thread3c">esempio thread3.c</uri>,, usiamo un metodo di inizializzazione
414 statico. Questo richiede la dichiarazione di una variabile pthread_mutex_t e
415 assegnarle il valore della costante PTHREAD_MUTEX_INITIALIZER:
416 </p>
417
418 <pre caption="Esempio di inizializzazione">
419 pthread_mutex_t mymutex=PTHREAD_MUTEX_INITIALIZER;
420 </pre>
421
422 <p>
423 Questo è abbastanza semplice. Ma si possono creare mutex anche dinamicamente.
424 Usate questo metodo dinamico ogni volta che il vostro codice alloca un nuovo
425 mutex usando malloc(). In questo caso il metodo di inizializzazione statico
426 non funzionerebbe e dovrebbe venir usata la routine pthread_mutex_init():
427 </p>
428
429 <pre caption="Creare un mutex in modo dinamico">
430 int pthread_mutex_init( pthread_mutex_t *mymutex, const
431 pthread_mutexattr_t*attr)
432 </pre>
433
434 <p>
435 Come potete notare, pthread_mutex_init accetta un puntatore a una regione di
436 memoria preventivamente allocata per inizializzarlo come mutex. Come secondo
437 argomento, può anche accettare un puntatore opzionale pthread_mutexattr_t.
438 Questa struttura può essere usata per impostare diversi attributi del mutex. Ma
439 di norma questi attributi non sono necessari, così generalmente si specifica
440 NULL.
441 </p>
442
443 <p>
444 Ogni volta che inizializzate un mutex usando pthread_mutex_init(), dovrebbe
445 essere distrutto usando pthread_mutex_destroy(). pthread_mutex_destroy() accetta
446 un unico puntatore a pthread_mutex_t e libera tutte le risorse impegnate dal
447 mutex al momento della sua creazione. State attenti che pthread_mutex_destroy()
448 non liberi la memoria usata per salvare pthread_mutex_t. Dipende da voi svuotare
449 la memoria. Ricordatevi anche che sia pthread_mutex_init() che
450 pthread_mutex_destroy() ritornano zero se tutto va bene.
451 </p>
452
453 </body>
454 </section>
455 <section>
456 <title>Usare le chiamate: locking</title>
457 <body>
458
459 <pre caption="Esempio di locking">
460 pthread_mutex_lock(pthread_mutex_t *mutex)
461 </pre>
462
463 <p>
464 pthread_mutex_lock() accetta un unico puntatore ad un mutex per bloccarlo. Se il
465 mutex fosse già bloccato, il chiamante andrà in sleep. Quando la funzione
466 ritorna il chiamante sarà (ovviamente) svegliato e a questo punto terrà anche il
467 lock. Questa chiamata può tornare uno zero, in caso di successo, o un codice di
468 errore diverso da zero in caso di fallimento.
469 </p>
470
471 <pre caption="Esempio di unlocking">
472 pthread_mutex_unlock(pthread_mutex_t *mutex)
473 </pre>
474
475 <p>
476 pthread_mutex_unlock() complementa pthread_mutex_lock() e sblocca un mutex ch
477 e il thread aveva già bloccato. Dovreste sempre sbloccare un mutex che avete
478 bloccato quando è sufficientemente sicuro (per aumentarne le prestazione). E non
479 dovreste mai sbloccare un mutex di cui non abbiate il blocco (altrimenti la
480 chiamata a pthread_mutex_unlock() fallirà con un valore di ritorno EPERM diverso
481 da zero).
482 </p>
483
484 <pre caption="Provando l'esempio di lock">
485 pthread_mutex_trylock(pthread_mutex_t *mutex)
486 </pre>
487
488 <p>
489 Questa chiamata è comoda quando volete bloccare un mutex mentre il vostro thread
490 sta facendo qualcos'altro perché il mutex è al momento bloccato. Quando chiamate
491 pthread_mutex_trylock() cercherete di bloccare il mutex. Se il mutex è al
492 momento sbloccato voi lo bloccate e questa funzione ritornerà zero. Tuttavia, se
493 il mutex è bloccato, questa chiamata non lo bloccherà. Ritornerà invece un
494 valore di errore EBUSY, diverso da zero. A questo punto proseguite con le vostre
495 attività e provate a bloccarlo più tardi.
496 </p>
497
498 </body>
499 </section>
500 <section>
501 <title>Aspettando le condizioni</title>
502 <body>
503
504 <p>
505 I mutex sono strumenti necessari per i programmi con thread, ma non possono fare
506 tutto. Cosa succede, ad esempio, se il vostro thread sta aspettando che si
507 verifichi una certa condizione su dei dati condivisi? Il vostro codice sblocca e
508 blocca ripetutamente il mutex, controllando ogni cambiamento del valore. Allo
509 stesso tempo sbloccherà velocemente il mutex così che altri possano fare i
510 cambiamenti necessari. Ma questo è un approccio orribile, perché questo thread
511 dovrà fare un busy loop per determinare un cambiamento in un ragionevole lasso
512 di tempo.
513 </p>
514
515 <p>
516 Potete mettere il thread chiamante in sleep per un po', diciamo tre secondi tra
517 ogni controllo, ma allora il vostro codice con thread non sarà reattivo in
518 maniera ottimale. Quello di cui avete bisogno è un modo per mettere in sleep un
519 thread mentre aspetta che alcune condizioni vengano a verificarsi. Una volta che
520 si verificano le condizioni avete bisogno di un metodo per svegliare i o il
521 thread che sta aspettando che quella condizione si verifichi. Se riuscite a fare
522 ciò il vostro codice con thread sarà veramente efficiente e non vincolerà
523 importanti bloccaggi di mutex. Questo è ciò che le variabili della condizione
524 POSIX possono fare per voi.
525 </p>
526
527 <p>
528 E le variabili della condizione POSIX sono l'argomento del mio prossimo
529 articolo, dove vi mostrerà esattamente come usarle. A quel punto avrete tutte le
530 risorse per creare sofisticati programmi con thread che modellano gruppi di
531 lavoro, linee di assembler e altro ancora. Nel nuovo articolo accelererò il
532 passo ora che avete più familiarità con i thread. Spero di riuscire ad inserire
533 un programma con thread ragionevolmente sofisticato alla fine del prossimo
534 articolo e parlando di cura delle condizioni, arrivederci!
535 </p>
536
537 </body>
538 </section>
539 </chapter>
540
541 <chapter id="resources">
542 <title>Risorse</title>
543 <section>
544 <body>
545
546 <ul>
547 <li>
548 Leggi la spiegazione ai thread POSIX di Daniel <uri
549 link="l-posix1.xml">Parte 1</uri> e <uri link="l-posix3.xml">Parte
550 3</uri>.
551 </li>
552 <li>
553 Leggete la documentazione su <uri
554 link="http://metalab.unc.edu/pub/Linux/docs/faqs/Threads-FAQ/html/">Linux
555 threads</uri>, di Sean Walton, KB7rfa.
556 </li>
557 <li>
558 Date sempre un'occhiata all'amichevole pagina del manuale LINUX di pthread
559 (<c>man -k pthread</c>).
560 </li>
561 <li>
562 Guardate <uri link="http://pauillac.inria.fr/~xleroy/linuxthreads/">The
563 LinuxThreads Library.</uri>
564 </li>
565 <li>
566 <uri link="http://www.users.itl.net.ua/~prool/proolix.html">Proolix</uri> è
567 un semplice sistema operativo POSIX-compliant per i8086+ in continuo
568 sviluppo.
569 </li>
570 <li>
571 Date un'occhiata al libro di David R. Butenhof <uri
572 link="http://www.amazon.com/exec/obidos/ASIN/0201633922/o/qid=961544788/sr=8-1/ref=aps_sr_b_1_1/002-2882413-1227240">
573 Programming with POSIX Threads</uri>, in cui lui affronta, tra le altre
574 cose, le possibili permutazioni del non usare i mutex.
575 </li>
576 <li>
577 Prendete il libro di W. Richard Stevens <!-- FIXME not available out
578 there,
579 commenting out and leaving finding it pleasure to readers<uri
580
581 link="http://devworks.krcinfo.com/WebForms/ProductDetails.aspx?ProductID=
582 0139498761">-->"UNIX Network Programming".
583 </li>
584 <li>
585 Trovate ulteriori risorse per sviluppatore Linux in <uri
586 link="http://www.ibm.com/developerworks/linux/">developerWorks Linux
587 zone</uri>.
588 </li>
589 <li>
590 Fatevi coinvolgere dalla comunità di developerWorks partecipando ai
591 <uri link="http://www.ibm.com/developerworks/blogs/">blog di
592 developerWorks</uri>.
593 </li>
594 <!-- FIXME Ugly advertisement
595 15:25 <rane> is that ok to put such advertisment at gentoo.org?
596 15:26 * neysx would not copy them
597 15:27 <SwifT> I wouldn't keep it
598 <li>
599 Purchase <uri
600
601 link="http://devworks.krcinfo.com/WebForms/ProductList.aspx?Search=Category&id=
602 300&parent=Linux">Linux
603 books at discounted prices</uri> in the Linux section of the
604 Developer Bookstore.
605 </li>
606 <li>
607 Order the no-charge SEK for Linux, a two-DVD set containing the latest IBM
608 trial software for Linux from DB2&registered;, Lotus&registered;,
609 Rational&registered;, Tivoli&registered;, and WebSphere&registered;.
610 </li>
611 <li>
612 Innovate your next Linux development project with <uri
613 link="http://www.ibm.com/developerworks/downloads/?S_TACT=105AGX03">IBM
614 trial software
615 </uri>, available for download directly from developerWorks.
616 </li>
617 -->
618 </ul>
619
620 </body>
621 </section>
622 </chapter>
623 </guide>
624
625
626
627 --
628 gentoo-commits@l.g.o mailing list