Geschiedenis van de kwestie:
Ondersteuning voor het werken met threads kwam beschikbaar in Perl 5.005, maar door de implementatieeigenaardigheden van de taal bleef het lange tijd experimenteel en ging het gepaard met een groot aantal bugs en beperkingen. Vanaf Perl 5.8 werd de module threads (en threads::shared) stabiel genoeg voor serieuze taken, maar het threadmodel van Perl verschilt sterk van veel andere programmeertalen: elke thread krijgt zijn eigen kopie van alle variabelen, en alleen expliciet gedeclareerde structuren via threads::shared zijn toegankelijk voor gedeeld gebruik.
Probleem:
"Gewone" variabelen zijn niet zichtbaar tussen threads vanwege de copy-on-write-semantiek. Pogingen om gegevens te distribureren zonder threads::shared leiden tot desynchronisatie van de toestand. Bij onjuist gebruik van blokkeringen bestaat het risico op races, deadlocks of inconsistente wijzigingen.
Oplossing:
Voor het gedeeld gebruik van variabelen declareer gedeelde variabelen via use threads::shared. Blokkeer toegang tot gedeelde gegevens met behulp van lock, vooral als meerdere threads gelijktijdig lezen/schrijven. Gebruik methoden join/detach om de levenscyclus van threads te beheren. Voor complexe structuren moet je elk element afzonderlijk gedeeld maken, omdat alleen het "bovenste niveau" geen volledige thread-veiligheid garandeert.
Voorbeeldcode:
use threads; use threads::shared; my $counter :shared = 0; my @threads; for (1..10) { push @threads, threads->create(sub { for (1..1000) { lock($counter); ++$counter; } }); } $_->join() for @threads; print "Counter: $counter ";
Belangrijkste kenmerken:
Biedt :shared thread-veiligheid zonder extra lock?
Nee. Het attribuut :shared biedt toegang tot de variabele tussen threads, maar wijzigingen (zoals ++ of --) zijn niet atomair. Lock is nodig voor elke kritieke sectie.
Kan een complexe structuur (array van hashes) gedeeld worden tussen threads met één :shared-directief?
Nee. Alleen het "bovenste niveau" van de array of hash zal shared zijn. Elk genest element moet ook shared worden gemaakt, anders zijn de interne structuren niet zichtbaar voor andere threads.
Kan een thread een andere thread beëindigen met een exit-aanroep?
Nee. Exit beëindigt het hele proces, niet een specifieke thread. Het stoppen van een thread gebeurt via exit binnen de thread of wordt beheerd door de logica van join/detach.
Twee threads verhogen gelijktijdig $counter :shared zonder lock. Het eindresultaat is lager dan verwacht (typisch lost update-probleem).
Voordelen:
Nadelen:
Implementatie van lock bij elke wijziging van de gedeelde variabele. Voor grote structuren genest lock element voor element.
Voordelen:
Nadelen: