Storia della questione
I thread (threads) sono stati introdotti in Perl come risposta alla necessità di organizzare calcoli concorrenti e lavoro parallelo con risorse in programmi multitasking. Il modulo standard threads è incluso in Perl a partire dalla versione 5.8, passando progressivamente da esperimenti con ithreads a threads::shared.
Problema
La prima difficoltà è che Perl non supporta nativamente i thread, come avviene in linguaggi come Java. I thread in Perl funzionano copiando lo stack e i dati di ogni thread, il che comporta sovraccarichi e rende impossibile l'utilizzo diretto delle variabili globali (eccetto per le variabili con una particolare associazione tramite threads::shared). Inoltre, Perl non garantisce il funzionamento indipendente dei thread in caso di scrittura simultanea dei dati senza esplicita sincronizzazione.
Soluzione
Per organizzare i thread si utilizza il modulo threads e un modulo aggiuntivo threads::shared per lo scambio di dati tra i thread. L'assicurazione della sincronizzazione e dell'integrità dei dati è a carico dello sviluppatore, spesso attraverso l'uso di locks.
Esempio di codice:
use threads; use threads::shared; my $counter :shared = 0; sub increment { lock($counter); $counter++; } my @threads; for (1..10) { push @threads, threads->create(\&increment); } $_->join for @threads; print "Counter: $counter ";
Caratteristiche chiave:
È possibile utilizzare qualsiasi variabile globale senza threads::shared e aspettarsi che i thread vedano i cambiamenti reciproci?
No. Le variabili globali vengono copiate in ogni thread individualmente. Per lo scambio, è possibile utilizzare solo threads::shared o altri IPC (tra processi).
È consentito eseguire fork e thread in un unico script Perl?
Non è consigliabile mescolare fork e threads, poiché ciò porta a bug imprevedibili e comportamenti instabili. Perl avverte ufficialmente dell'uso simultaneo di queste tecniche.
È possibile passare strutture dati complesse tra thread tramite riferimenti standard?
No. Perl non copia ricorsivamente le strutture nidificate automaticamente, e tali tentativi portano a errori o a risultati non intuitivi. Ciò richiede una copia profonda e l'uso di risorse condivise.
Uno sviluppatore ha creato una semplice coda tramite un array, aggiornato simultaneamente da più thread senza threads::shared. I dati venivano spesso danneggiati, generando risultati errati nell'esecuzione del programma.
Vantaggi:
Svantaggi:
Utilizzo di threads::shared con locks, l'intera coda era dichiarata come condivisa e la sincronizzazione avveniva tramite lock. Il programma funzionava in modo stabile, anche sotto carico intenso.
Vantaggi:
Svantaggi: