-+  Associazione
-+  Documenti
 |-  Modern Perl
 |-  Bibliografia
 |-  Articoli
 |-  Talk
 |-  Perlfunc
 |-  F.A.Q.
 |-  F.A.Q. iclp
-+  Eventi
-+  Community
-+  Blog
-+  Link
Corso di Perl



 

Assegnazione palline in un tennis club di Michele Beltrame

Versione stampabile.

1. Introduzione 2. Codice Sorgente (parte 1) 3. Discussione (parte 1) 4. Codice sorgente (parte 2: subroutine) 5. Discussione sulle subroutine 6. Estensioni 

Discussione sulle subroutine

Analizziamo ora le operazioni compiute da ciascun singolo thread/giocatore. È opportuno ricordare che, al momento della creazione di un thread, tutti i dati (scalari, array, funzioni, e quant'altro) presenti nel programma in quell'istante vengono clonati: di fatto viene creato un programma uguale all'originale, che gira come un thread dipendente dal programma principale. Dunque, tutti i dati sono separati, fatta eccezione per quelli esplicitamente condivisi. Nel nostro caso viene condivisa solo la variabile $palline, che indica le palline che il tennis club ha a disposizione in un determinato istante: questo valore è infatti unico, ed ogni thread deve potervi accedere in scrittura, secondo la modalità che verrà spiegata in seguito.

La subroutine che costituisce il codice principale di ciascun thread è giocatore(). In essa viene avviato un loop infinito, ogni iterazione del quale rappresenta una partita del giocatore, divisa in tre fasi: richiesta delle palline, gioco, restituzione delle palline. Il numero di palline è determinato estraendo un numero casuale compreso tra 1 e $pallinemax, in modo da rendere diversa ogni richiesta da quella precedente. A questo punto le palline vengono richieste tramite la funzione chiedi_palline(), che ritorna il numero delle palline che sono state effettivamente assegnate al thread/giocatore, oppure 0 in caso di mancata assegnazione. In caso appunto l'assegnazione non sia stata possibile (per via della mancanza delle palline necessarie) viene atteso un certo tempo (definito dalla variabile molto opportunamente chiamata $tempobar), e poi esse vengono richieste di nuovo, finché esse non vengono assegnate. Chiaramente, durante questi secondi, un altro thread/giocatore ha il tempo di restituire le sue palline, e forse un altro ancora riesce a richiederle prima che tale tempo sia trascorso. Una volta ottenute le palline, il programma si ferma per un tempo determinato in maniera casuale tra un secondo ed il contenuto di $tempomax. Trascorso questo intervallo, le palline vengono restituite con una chiamata a restituisci_palline(). Dopo una pausa di $tempoidl secondi, il ciclo infinito riparte.

Il clou del programma risiede nella funzione chiedi_palline(), che si occupa di assegnare un certo numero di palline a ciascun thread/giocatore. Anzitutto, è necessario effettuare il lock della variabile condivisa $palline, cioè richiederne l'utilizzo esclusivo. Questa operazione è strettamente necessaria per evitare delle race condition, cioè situazioni in cui più di un thread accede allo stesso dato in contemporanea. Prendiamo infatti in esame la linea di codice in cui viene decrementato il numero di palline disponibili:

 $palline -= $pallineass

L'operatore svolge fondamentalmente due operazioni su $palline: ne legge il valore e poi lo decrementa del valore di $pallineass. Tra queste due operazioni, in caso non vi fosse un lock sulla variabile, un altro thread (o più di uno) potrebbe effettuare a sua volta un'operazione. Ad esempio, poniamo che $palline valga 27, e che un giocatore ne richieda 4 e l'altro 5; alla fine di ciò $palline dovrebbe assumere valore 18. Senza un lock potrebbe configurarsi una situazione del genere:

 THREAD1: legge $palline
 THREAD2: legge $palline
 THREAD1: decrementa $palline => 23
 THREAD2: decrementa $palline => 22

Alla fine $palline assumerebbe valore 22, annullando di fatto il decremento effettuato dal primo thread. Un modo per prevenire queste situazioni è, appunto, l'utilizzo di un lock sulla variabile che si deve gestire:

lock ($palline);

Con la chiamata a lock() viene richiesta l'aasegnazione di un lock sulla variabile passata come parametro. Se non esiste un precedente lock su di essa, esso viene concesso e l'esecuzione del programma va avanti; se è presente un lock da parte di un altro thread, il thread corrente si blocca in attesa che tale lock venga rilasciato. È fondamentale tenere a mente che lock() non previene in alcun modo accessi alla variabile passatagli come parametro da parte di altri thread, ma semplicemente causa il blocco delle chiamate a lock() da parte di altri thread sulla stessa variabile. È dunque indispensabile che tutti i thread che utilizzano tale variabile condivisa ne chiedano il lock prima di utilizzarla.

Ottenuto il lock, le palline vengono assegnate in base ad una policy. Nel programma sono incluse due funzioni, policy1() e policy2(): è possibile utilizzare una oppure l'altra; la prima assegna semplicemente le palline richieste ad ogni thread/giocatore (se ve ne sono a disposizione), l'altra è un po' più complessa e, a seconda delle palline rimaste, ne può assegnare un numero inferiorie rispetto a quelle richieste. Se l'assegnazione va a buon fine, può essere effettuato il decremento della variabile. Il lock su $palline sparisce quando la chiamata a lock() esce dallo scope, in questo caso al termine della funzione. L'uscita dallo scope rappresenta l'unica via per togliere un lock ad una variabile, in quanto non esiste alcuna funzione unlock(). Notate che è necessario chiamare lock() prima dell'assegnazione delle palline secondo la policy scelta, poiché tale operazione implica la lettura del numero di palline correnti, che poi non deve essere variato da altri thread fino a che esso non viene eventualmente decrementato dal thread corrente.

La funzione restituisci_palline() è molto più semplice: dopo aver ottenuto l'obbligatorio lock su $palline, essa semplicemente incrementa $palline del numero di palline restituire (passato come parametro).

‹‹ Codice sorgente (parte 2: subroutine)

Estensioni ››

D:
Progetti e documenti in rilievo
Corso di Perl Progetto pod2it
D:
La ML di Perl.it
mongers@perl.it è la lista ufficiale di Perl Mongers Italia per porre quesiti di tipo tecnico, per rimanere aggiornato su meeting, incontri, manifestazioni e novità su Perl.it.
Iscriviti!
D:
Annunci Google