Background:
Thread support was introduced in Perl 5.005, but due to the language's implementation details, it remained experimental for a long time, accompanied by numerous bugs and limitations. Starting from Perl 5.8, the threads (and threads::shared) module became stable enough for serious tasks, however, Perl's threading model differs significantly from many other programming languages: each thread gets its own copy of all variables, and only explicitly declared structures via threads::shared are accessible for shared access.
The Issue:
"Regular" variables are not visible between threads because of copy-on-write semantics. Attempting to share data without threads::shared leads to desynchronization of state. Incorrect use of locks can lead to race conditions, deadlocks, or inconsistent modifications.
The Solution:
To share variables, declare shared variables through use threads::shared. Lock access to shared data using lock, especially if multiple threads read/write simultaneously. Use join/detach methods to manage the lifecycle of threads. For complex structures, declare each shared element separately, as only the "top-level" does not ensure complete thread safety.
Code example:
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 ";
Key features:
Does :shared ensure thread safety without additional locks?
No. The :shared attribute provides access to the variable between threads, but modifications (e.g., ++ or --) are not atomic. A lock is necessary for each critical section.
Can a complex structure (array of hashes) be shared between threads with a single :shared directive?
No. Only the “top level” of the array or hash will be shared. Each nested element must also be made shared; otherwise, internal structures will not be visible to other threads.
Can one thread kill another thread by calling exit?
No. exit terminates the entire process, not a single thread. Stopping a thread is done via exit inside the thread or managed through join/detach logic.
Two threads simultaneously increment $counter :shared without locks. The final result is less than expected (a typical lost update problem).
Pros:
Cons:
Implementing a lock on each change of the shared variable. For large structures, nested locks element-wise.
Pros:
Cons: