public inbox for gentoo-docs-it@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-docs-it] Posix Thread Explained, Part 1 - traduzione
@ 2007-05-12  7:01 Andrea Veroni
  2007-05-12 12:02 ` Davide Cendron
  0 siblings, 1 reply; 2+ messages in thread
From: Andrea Veroni @ 2007-05-12  7:01 UTC (permalink / raw
  To: gentoo-docs-it

[-- Attachment #1: Type: text/plain, Size: 490 bytes --]

Posto la mia traduzione per la revisione finale, consigli, segnalazione di 
eventuali errori di forma e/o contenuto (come e' oramai prassi) prima del 
consueto bug report. Essendo un articolo in cui lo scrittore parla in prima 
persona ho lasciato la forma colloquiale, perche' renderlo impersonale non 
rendeva molto l'idea...Se pero' fa schifo posso sempre cambiarlo :)

Chiedo anche di poter tradurre l-posix2.xml, cosi' continuo con la saga dei 
thread posix che sono tanto carucci :D


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: l-posix1.xml --]
[-- Type: text/xml; charset="us-ascii"; name="l-posix1.xml", Size: 23554 bytes --]

<?xml version='1.0' encoding="UTF-8"?>
<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/doc/it/articles/l-posix1.xml,v 1.4 2005/10/09 17:13:23 rane Exp $ -->
<!DOCTYPE guide SYSTEM "/dtd/guide.dtd">

<guide link="/doc/it/articles/l-posix1.xml" lang="it" disclaimer="articles">
<title>POSIX threads explained, parte 1</title>

<author title="Autore">
  <mail link="drobbins@gentoo.org">Daniel Robbins</mail>
</author>
<author title="Traduttore">
  <mail link="andreaveroni@tiscalinet.it">Andrea Veroni</mail>
</author>

<abstract>
I thread POSIX (Portable Operating System Interface) sono un ottima maniera per 
incrementare la reattività e le prestazioni del proprio codice. In questa serie,
Daniel Robbins mostra esattamente come utilizzare i thread nel vostro codice.
Verranno svelati dettagli del retroscena, cosicchè alla fine della serie sarete 
veramente pronti per creare il vostro programma multithread.
</abstract>

<!-- La versione originale di questo articolo è stata pubblicata su IBM 
developerWorks, ed è di proprietà della Westtech Information Services.
Questo documento è una versione aggiornata dell'articolo originale, e 
contiene diversi miglioramenti fatti dal Gentoo Linux Documentation Team -->

<version>1.2</version>
<date>2005-10-09</date>

<chapter>
<title>Uno strumento semplice e veloce per la condivisione della memoria</title>
<section>
<title>I Thread sono divertenti</title>
<body>

<p>
Sapere come usare correttamente i thread dovrebbe far parte del repertorio di
ogni buon programmatore. I thread sono simili ai processi. L'esecuzione dei 
thread, similmente a quella dei processi, è ripartita dal kernel in intervalli 
di tempo. Nei sistemi uniprocessore il kernel sfrutta il time slice per simulare 
l'esecuzione simultanea di piu' thread nella stessa maniera in cui sfrutta il time 
slice per i processi. E attualmente, sui sistemi multiprocessore, i thread possono
essere eseguiti contemporaneamente, esattamente come due o piu' processi.
</p>

<p>
E perche' il multithreading è preferibile a più processi indipendenti per la 
maggior parte dei compiti cooperativi? Bene, i thread condividono lo stesso spazio 
in memoria. Thread indipendenti possono accedere alle stesse variabili.in memoria.
Infatti tutti i thread contenuti nel programma possono leggere e scrivere le stesse 
variabili dichiarate globalmente. Se avete mai scritto del codice "non grezzo" che 
utilizza la funzione fork(), riconoscerete l'importanza di questo strumento. Perchè? 
Mentre fork() permette di dare vita a più processi, crea anche il seguente problema 
di comunicazione: come far dialogare fra loro più processi, ognuno dei quali ha un 
proprio spazio in memoria. Non esiste una soluzione semplice a questo problema. 
Nonostante ci siano molti tipi differenti di comunicazione fra i processi locale 
(IPC), tutti presentano gli stessi due inconvenienti:
</p>

<ul>
  <li>
    Impongono al kernel una specie di overhead in più, abbassando le prestazioni.
  </li>
  <li>
    In quasi tutte le situazioni l'IPC non è un ampliamento "naturale" del codice.
    Spesso accresce drasticamente la complessità del programma.
  </li>
</ul>

<p>
Ulteriore scocciatura: overhead e complicazioni non sono cose belle. Se vi è mai
capitato di dover apportare grosse modifiche ad uno dei vostri programmi per 
fare in modo che supporti IPC, apprezzerete senz'altro il semplice approccio di 
condivisione della memoria che i thread mettono a disposizione. I thread POSIX 
non necessitano di costose e complicate chiamate a lunga distanza perchè è come 
se tutti i nostri thread vivessero nella stessa casa. Con un po' di sincronizzazione,
tutti i vostri thread possono leggere e modificare le strutture dati presenti nel 
programma. Non è necessario far transitare i dati attraverso un file descriptor o 
comprimerli in una piccola area di memoria condivisa. Per questo motivo solamente
dovreste prendere in considerazione il modello con un processo multithread piuttosto 
che il modello multiprocesso con singoli thread.
</p>

</body>
</section>
<section>
<title>I thread sono leggeri</title>
<body>

<p>
Ma c'è altro. I thread risultano inoltre essere estremamente leggeri. Confrontati
alla fork() standard, producono molto meno overhead. Inoltre il kernel non necessita 
di creare un'ulteriore copia autonoma dello spazio di memoria relativo al processo, 
dei file descriptor, ecc. Ciò comporta un notevole risparmio del tempo di CPU, rendendo 
la creazione dei thread da decine a centinaia di volte più veloce che la creazione 
di nuovi processi. Proprio grazie a ciò, è possibile utilizzare un intero gruppo di 
thread senza doversi preoccupare di un eventuale overhead della CPU o della memoria.
Non si ha un grosso utilizzo della CPU come si ha con una fork(). Questo significa 
che potete dare vita ai thread in qualsiasi momento abbia senso all'interno del 
programma.
</p>

<p>
Ovviamente, proprio come i processi, i thread trarranno vantaggio dalla presenza di 
più CPU. Questa è veramente un'ottima caratteristica se il software è progettato per 
essere utilizzato su macchine multiprocessore (se il software è open source, 
probabilmente finirà col girare soltanto su alcune di quelle). Le prestazioni di 
alcune tipologie di programmi che utilizzano i thread (in modo particolare quelli 
che fanno uso intenso della CPU) salirà in modo abbastanza lineare relativamente al 
numero dei processori presenti nel sistema. Se state scrivendo un programma che fa un 
uso intenso della CPU , certamente cercherete un modo per poter utilizzare i thread nel 
vostro codice. Una volta esperti nello scrivere codice contenente thread, sarete capaci, 
scrivendo codice, di affrontare le sfide in modi nuovi e creativi, senza una moltitudine 
di IPC red tape and miscellaneous mumbo-jumbo. Tutti questi benefici lavorano in sinergia 
per rendere la programmazione multithread divertente, veloce e flessibile.
</p>

</body>
</section>
<section>
<title>Ora penso di essere un clone</title>
<body>

<p>
Se avete mai fatto parte del mondo della programmazione Linux almeno per un momento, potreste
conoscere la chiamata di sistema __clone(). __clone() e' simile a fork(), ma consente di 
svolgere molti dei compiti che anche i thread possono svolgere. Per esempio, con __clone()
potete selettivamente condividere parte del contesto di esecuzione del processo padre (spazio 
in memoria, descrittori dei file, ecc.) con un nuovo processo figlio. E ciò e' un bene. Ma ci 
sono anche cose negative a proposito di __clone(). Come riporta la pagina del manuale di __clone:
</p>

<pre caption="Citazione dalla pagina del manuale di __clone()">
    "La chiamata __clone è propria di Linux e non dovrebbe essere utilizzata in programmi il 
    cui obiettivo è la portabilità. Programmando applicazioni che sfruttano i thread (thread 
    di controllo multipli nello stesso spazio di memoria), è preferibile utilizzare una 
    libreria che implementi il thread API POSIX 1003.1c, come la libreria thread di Linux. 
    Vedi pthread_create(3)."
</pre>

<p>
Così, anche se __clone() offre gran parte dei vantaggi che offrono i thread, non è 
portabile. Ciò non significa che non dovreste usarla nel vostro codice. Ma dovreste 
valutare ciò quando pensate di utilizzare __clone() nel vostro software. Fortunatamente, 
come riporta la pagina del manuale di __clone(), c'è un'alternativa migliore: i thread 
POSIX. Quando avete intenzione di scrivere codice portabile e multithread, codice che 
funzioni sotto Solaris, FreeBSD, Linux, e altri, i thread POSIX sono la giusta strada da 
seguire.
</p>

</body>
</section>
<section>
<title>Iniziando con i thread</title>
<body>

<p>
Ecco un semplice programma che sfrutta i thread POSIX:
</p>

<pre caption="Programma di esempio che sfrutta i thread POSIX">
#include &lt;pthread.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;

void *thread_function(void *arg) {
  int i;
  for ( i=0; i&lt;20; i++ ) {
    printf("Thread says hi!\n");
    sleep(1);
  }
  return NULL;
}

int main(void) {

  pthread_t mythread;
  
  if ( pthread_create( &amp;mythread, NULL, thread_function, NULL) ) {
    printf("error creating thread.");
    abort();
  }

  if ( pthread_join ( mythread, NULL ) ) {
    printf("error joining thread.");
    abort();
  }

  exit(0);

}
</pre>

<p>
Per compilare questo programma, semplicemente salvare il file come "thread1.c" e digitare:
</p>

<pre caption="Compilare il programma">
$ <i>gcc thread1.c -o thread1 -lpthread</i>
</pre>

<p>
Eseguirlo digitando:
</p>

<pre caption="Eseguire il programma">
$ <i>./thread1</i>
</pre>

</body>
</section>
<section>
<title>Capire thread1.c</title>
<body>

<p>
<path>thread1.c</path> è un semplicissimo programma che utilizza i thread. Anche se 
non fa nulla di utile, vi aiuterà a capire come funzionano i thread. Ora diamo 
un'occhiata passo passo a ciò che fa questo programma. In main() per prima cosa 
dichiariamo una variabile chiamata mythread, che ha un tipo pthread_t. Il tipo 
pthread_t, definito in <path>pthread.h</path>, e' spesso chiamato "thread id" 
(comunemente abbreviato a "tid"). Pensate a ciò come una specie di gestore di thread.
</p>

<p>
Dopo che mythread è stato dichiarato (ricordare che mythread è soltanto un "tid", 
o un controllo al thread che stiamo per creare), chiamiamo la funzione pthread_create 
per creare un vero e proprio thread. Non fatevi trarre in inganno dal fatto che 
pthread_create() è all'interno di un costrutto "if". Poichè pthread_create() ritorna 
zero in caso di successo e un valore diverso da zero in caso di insuccesso, collocare 
la chiamata alla funzione all'interno di un if() è soltanto una maniera elegante di 
scoprire un insuccesso della chiamata di pthread_create(). E ora diamo un'occhiata 
agli argomenti passati a pthread_create. Il primo è un puntatore a mythread, 
&amp;mythread. Il secondo argomento, al momento settato NULL, può essere 
utilizzato per definire alcuni attributi del nostro thread. Poichè gli attributi 
di default del thread per noi funzionano bene, lo settiamo semplicemente a NULL.
</p>

<p>
Il nostro terzo argomento è il nome della funzione che il nuovo thread eseguirà
una volta avviato. In questo caso il nome della funzione è thread_function().
Quando thread_function() ritorna, il nostro nuovo thread terminerà. In questo 
esempio la nostra funzione thread non esegue nulla di particolare. Stampa solamente 
a video "Thread says hi!" per 20 volte e poi esce. Notate che thread_function() accetta 
void * come argomento e ritorna void * come valore di ritorno.
Questo dimostra che è possibile utilizzare un void * per passare una quantita' arbitraria 
di dati al nostro nuovo thread, e che il nostro nuovo thread può ritornare una quantita' 
arbitraria di dati quando termina. E ora come possiamo passare al nostro thread un 
argomento arbitrario? Semplice. Si utilizza il quarto argomento per chiamata a 
pthread_create(). In questo esempio è settato a NULL perchè non serve passare nessun 
dato alla nostra grezza thread_function().
</p>

<p>
Come potete aver intuito, il programma sarà composto da due thread dopo che 
pthread_create() ha ritornato con successo. Aspetta un minuto, due thread? Non abbiamo 
creato solamente un singolo thread? Si, certo. Ma anche il nostro programma principale è 
considerato un thread. Pensatela in questo modo: se viene scritto un programma senza 
assolutamente utilizzare i thread POSIX, il programma sarà composto da un singolo thread 
(questo singolo thread è chiamato thread "principale"). Creando un nuovo thread ora 
abbiamo un totale di due thread nel nostro programma.
</p>

<p>
Immagino che abbiate almeno due importanti domande da fare a questo punto. La prima 
è cosa il thread principale faccia dopo la creazione del nuovo thread. Continua ed 
esegue in sequenza la riga successiva del nostro programma (in questo caso la linea 
è "if ( pthread_join(...))"). La seconda domanda a cui potreste pensare è cosa succceda 
al nuovo thread una volta che esiste. Si ferma e aspetta di essere unificato o "riunito" 
con un altro thread come parte del proprio processo di pulizia.
</p>

<p>
OK, ora di nuovo a pthread_join(). Esattamente come pthread_create() divide il 
singolo thread in due thread, pthread_join() unifica due thread in un singolo thread. 
Il primo argomento passato a pthread_join() è il nostro "tid" mythread. Il secondo 
argomento è un puntatore ad un puntatore vuoto. Se il puntatore vuoto non è NULL, 
pthread_join() metterà il valore di ritorno di void * del thread nella locazione 
specificata. Poichè non ci interessa il valore di ritorno di pthread_function(), 
lo settiamo a NULL.
</p>

<p>
Noterete che thread_function() impiega 20 secondi per arrivare al termine. Molto 
prima che thread_function() completi l'esecuzione, il thread principale ha già 
chiamato pthread_join(). Quando questo succede il thread principale si blocca (va in
sleep) e aspetta il completamento di thread_function(). Una volta che thread_function()
ha competato il suo compito, pthread_join() ritornerà. Ora il programma ha di nuovo 
un thread principale. Quando il nostro programma esce, tutti i nuovi thread sono passati 
per la funzione pthread_join(). Questo è esattamente il modo in cui vi dovreste comportare 
con ogni nuovo thread creato all'interno dei vostri programmi. Se un nuovo thread non è 
ricongiunto continuerà a diminuire il numero massimo di thread eseguibili dal vostro 
sistema. Questo significa che la dovuta pulizia, se non effettuata a dovere, 
probabilmente causerà un fallimento delle nuove chiamate a pthread_create.
</p>

</body>
</section>
<section>
<title>Niente padri, niente figli</title>
<body>

<p>
Se avete utilizzato la chiamata a sistema fork() probabilmente avete familiarità 
col concetto di processi padre e figlio. Quando un processo genera un nuovo processo 
utilizzando fork(), il nuovo processo viene considerato figlio e il processo originale 
viene considerato padre. Questo crea una relazione gerarchica che può essere conveniente, 
in modo particolare durante l'attesa del termine di un processo figlio. La funzione 
waitpid(), per esempio, comunicherà al processo corrente di aspettare il termine di uno 
dei processi figlio. waitpid() è utilizzata per implementare una semplice routine di 
pulizia nei processi padre.
</p>

<p>
Le cose si fanno un po' più interessanti con i thread POSIX. Potreste aver notato
che finora ho volutamente evitato di utilizzare i termini "thread padre" e "thread 
figlio". Tutto ciò perchè con i thread POSIX queste relazioni gerarchiche non esistono. 
Mentre un thread principale può creare un nuovo thread, e questo nuovo thread può 
creare un altro nuovo thread, lo standard dei thread POSIX vede tutti i vostri thread 
come un singolo insieme di risorse, uguali fra loro. Per questo motivo il concetto di 
attesa dell'uscita di un thread figlio non ha senso. Lo standard dei thread POSIX non 
registra nessuna informazione della "famiglia". Questa mancanza di una genealogia ha 
un'implicazione più grande: se si vuole attendere il termine di un thread, è necessario 
specificare quale si sta aspettando passando l'identificatore appropriato a pthread_join(). 
La libreria dei thread non può immaginarselo al posto vostro.
</p>

<p>
Per molte persone questa non è una gran bella notizia perchè può rendere più complicati 
programmi composti da più di due thread. Non fatevi intimorire. Lo standard dei thread POSIX 
fornisce tutti gli strumenti utili per gestire in maniera elegante thread multipli. 
Allo stato attuale, il fatto che non ci siano relazioni padre/figlio apre strade nuove 
e creative di utilizzare i thread nei vostri programmi. Per esempio, se abbiamo un thread 
chiamato thread 1, e thread 1 crea a sua volta un thread chiamato thread 2, non è necessario 
allo stesso thread 1 chiamare pthread_join() per il thread 2. Qualsiasi altro thread nel 
programma può farlo. Ciò permette interessanti possibilità di scrivere codice che sfrutta 
pesantemente il multithread. Potete, per esempio, creare una "dead list" globale che 
contenga tutti i thread fermi e poi avere uno speciale thread di pulizia che semplicemente 
aspetta che un elemento sia aggiunto alla lista. Il thread di pulizia chiama pthread_join() 
per unificarsi con se stesso. Ora l'intera pulizia sarà gestita in modo efficente e armonioso 
in un unico thread.
</p>

</body>
</section>
<section>
<title>Nuoto sincronizzato</title>
<body>

<p>
E' giunto finalmente il momento di dare un'occhiata a codice che compia qualcosa 
di un po' inaspettato. Ecco thread2.c:
</p>

<pre caption="thread2.c">
#include &lt;pthread.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;

int myglobal;

 void *thread_function(void *arg) {
  int i,j;
  for ( i=0; i&lt;20; i++ ) {
    j=myglobal;
    j=j+1;
    printf(".");
    fflush(stdout);
   sleep(1);
    myglobal=j;
  }
  return NULL;
}

int main(void) {

  pthread_t mythread;
  int i;

  if ( pthread_create( &amp;mythread, NULL, thread_function, NULL) ) {
    printf("error creating thread.");
    abort();
  }

  for ( i=0; i&lt;20; i++) {
    myglobal=myglobal+1;
    printf("o");
    fflush(stdout);
    sleep(1);
  }

  if ( pthread_join ( mythread, NULL ) ) {
    printf("error joining thread.");
    abort();
  }

  printf("\nmyglobal equals %d\n",myglobal);

  exit(0);

}
</pre>

</body>
</section>
<section>
<title>Capire thread2.c</title>
<body>

<p>
Questo programma, proprio come il primo, crea un nuovo thread. Sia il thread 
principale che il nuovo thread vanno ad incrementare per 20 volte una variabile 
globale chiamata myglobal. Ma il programma stesso produce qualche risultato 
inaspettato. Compilarlo digitando:
</p>

<pre caption="Compilare il programma">
$ <i>gcc thread2.c -o thread2 -lpthread</i>
</pre>

<p>
ed eseguirlo:
</p>

<pre caption="Esecuzione">
$ <i>./thread2</i>
..o.o.o.o.oo.o.o.o.o.o.o.o.o.o..o.o.o.o.o
myglobal equals 21
</pre>

<p>
Abbastanza inaspettato! Poichè myglobal parte da zero, e sia il thread principale 
che il nuovo thread la incrementano di 20, dovremmo vedere myglobal uguale a 40 
alla fine del programma. Dato che myglobal è uguale a 21 sappiamo che sta succedendo 
qualcosa di strano. Ma cosa?
</p>

<p>
Rinunciato? OK, vi mostrerò cosa succede. Date un'occhiata a thread_function(). 
Notate come copiamo myglobal in una variabile locale chiamata "j"? E notate 
in che modo incrementiamo j, poi pausa per un secondo e soltanto dopo copiamo il 
nuovo valore di j in myglobal? Questa è la chiave. Immaginate cosa succederebbe se 
il thread principale incrementasse myglobal soltanto <e>dopo</e> che il nuovo thread 
ha copiato il valore di myglobal in j. Quando thread_function() scrive di nuovo 
il valore di j in myglobal, va a sovrascrivere le modifiche fatte dal thread 
principale. 
</p>

<p>
Scrivendo programmi che sfruttano i thread, vorrete evitare inutili side effect 
simili a quello appena visto, perchè sono una perdita di tempo (eccezion fatta 
se state scrivendo un articolo sui thread POSIX, ovviamente :). E ora cosa 
si può fare per eliminare questo problema?
</p>

<p>
Dal momento che il problema si verifica perchè myglobal è stata copiata in j e 
fermata per un secondo prima di riscriverla, possiamo provare ad evitare l'uso di una 
variabile locale incrementando myglobal in modo diretto. Ma mentre questa soluzione 
probabilmente funzionerà in questo particolare esempio, non è corretta. E se stiamo 
svolgendo un'operazione matematica relativamente complessa su myglobal invece che 
semplicemente incrementarla, certamente fallirà. Ma perchè?
</p>

<p>
Per capire il problema, è necessario ricordare che i thread vanno in esecuzione in 
maniera simultanea. Anche su una macchina uniprocessore (dove il kernel utilizza il 
time slice per simulare un multitasking reale) possiamo, dalla prospettiva di un 
programmatore, immaginare entrambi i thread in esecuzione contemporaneamente. thread2.c 
presenta problemi perchè il codice all'interno di thread_function() si basa sul fatto 
che myglobal non viene modificata per la durata di 1 secondo prima di essere incrementata. 
Ci servono alcuni procedimenti per far sì che un thread comunichi all'altro di "bloccarsi" 
fintanto che non vengono effettuate delle modifiche a myglobal. Vi mostrerò in modo esatto 
come fare nel mio prossimo articolo. Alla prossima.
</p>

</body>
</section>
</chapter>

<chapter>
<title>Risorse</title>
<section>
<body>

<ul>
  <li>
    Leggi la spiegazione ai thread POSIX di Daniel <uri link="l-posix2.xml">Part 2</uri>
    and <uri link="l-posix3.xml">Part 3</uri>.
  </li>
  <li>
    Leggi la documentazione su <uri
    link="http://metalab.unc.edu/pub/Linux/docs/faqs/Threads-FAQ/html/">Linux
    threads</uri>, by Sean Walton, KB7rfa 
  </li>
  <li>
    Un <uri
    link="http://www.math.arizona.edu/swig/pthreads/threads.html">tutorial</uri>
    sui thread POSIX scritto da Mark Hays presso la University of Arizona
  </li>
  <li>
    In <uri link="http://hwaci.com/sw/pttcl/pttcl.html">An Introduction to
    Pthreads-Tcl</uri>, controllate i cambiamenti a Tcl che la rendono idonea 
    all'utilizzo con i thread POSIX
  </li>
  <li>
    Un altro tutorial, <uri 
    link="http://dis.cs.umass.edu/~wagner/threads_html/tutorial.html">Getting
    Started with POSIX Threads</uri>, scritto da Tom Wagner and Don Towsley 
    presso il Computer Science Department della University of Massachusetts, 
    Amherst 
  </li>
  <li>
    Date sempre uno sguardo alla amichevole pagina del manuale di Linux di pthread 
    (<c>man -k pthread</c>)
  </li>
  <li>
    <uri link="http://moss.csc.ncsu.edu/~mueller/pthreads/">FSU PThreads</uri> è una 
    libreria C che implementa i thread POSIX per SunOS 4.1.x, Solaris 2.x, SCO
    UNIX, FreeBSD, Linux, and DOS
  </li>
  <li>
    Riferimento alla home page di <uri
    link="http://www.sai.msu.su/sal/C/2/PCTHREADS.html">thread POSIX e DCE per 
    Linux</uri>
  </li>
  <li>
    Guardate <uri link="http://pauillac.inria.fr/~xleroy/linuxthreads/">La
    libreria LinuxThreads</uri>
  </li>
  <li>
    <uri link="http://www.users.itl.net.ua/~prool/proolix.html">Proolix</uri> è un 
    semplice sistema operativo per i8086 POSIX-compliant in permanente sviluppo 
  </li>
  <li>
    Date un'occhiata al libro di David R. Butenhof <uri
    link="http://www.amazon.com/exec/obidos/ASIN/0201633922/o/qid=961544788/sr=8-1/ref=aps_sr_b_1_1/002-2882413-1227240">
    Programming with POSIX Threads</uri>, in cui egli ricopre, fra le altre 
    cose, i possibili cambiamenti nel non utilizzare i mutex
  </li>
  <li>
    Cercate il libro di W. Richard Stevens <uri
    link="http://search.borders.com/fcgi-bin/db2www/search/search.d2w/Details?&amp;mediaType=Book&amp;prodID=2362607">UNIX
    Network Programming: Network APIs: Sockets and XTI, Volume 1</uri>
  </li>
</ul>

</body>
</section>
</chapter>

</guide>

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [gentoo-docs-it] Posix Thread Explained, Part 1 - traduzione
  2007-05-12  7:01 [gentoo-docs-it] Posix Thread Explained, Part 1 - traduzione Andrea Veroni
@ 2007-05-12 12:02 ` Davide Cendron
  0 siblings, 0 replies; 2+ messages in thread
From: Davide Cendron @ 2007-05-12 12:02 UTC (permalink / raw
  To: gentoo-docs-it

[-- Attachment #1: Type: text/plain, Size: 929 bytes --]

Il Saturday 12 May 2007 09:01:40 Andrea Veroni ha scritto:
> Posto la mia traduzione per la revisione finale, consigli, segnalazione di
> eventuali errori di forma e/o contenuto (come e' oramai prassi) prima del
> consueto bug report. Essendo un articolo in cui lo scrittore parla in prima
> persona ho lasciato la forma colloquiale, perche' renderlo impersonale non
> rendeva molto l'idea...Se pero' fa schifo posso sempre cambiarlo :)

Ok, ci dò un'occhiata appena posso, e poi ti faccio sapere! :)

>
> Chiedo anche di poter tradurre l-posix2.xml, cosi' continuo con la saga dei
> thread posix che sono tanto carucci :D

Ok, così inoltre tutto il blocco di articoli risulterà più "omogeneo" come 
traduzione (essendo stato tradotto dalla stessa persona).

articles/l-posix2.xml tuo, grazie!

-- 
Davide Cendron

Gentoo Documentation Project
Italian Follow Up Translator

http://www.gentoo.org/doc/it/

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2007-05-12 12:03 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-05-12  7:01 [gentoo-docs-it] Posix Thread Explained, Part 1 - traduzione Andrea Veroni
2007-05-12 12:02 ` Davide Cendron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox