threads::shared(3perl)
π NAME π
threads::shared β the Perl extension for sharing data structures between threads. bestie that's the whole point of it, and it's so real. β¨
Oh also, hi, welcome: this is the page for threads::shared from the Perl Programmers Reference Guide, section 3perl. π
πΈ VERSION πΈ
This document describes threads::shared version 1.73. that's the one, no cap. π
β¨ SYNOPSIS β¨
okay so here's the whole vibe, look:
use threads;
use threads::shared;
my $var :shared;
my %hsh :shared;
my @ary :shared;
my ($scalar, @array, %hash);
share($scalar);
share(@array);
share(%hash);
$var = $scalar_value;
$var = $shared_ref_value;
$var = shared_clone($non_shared_ref_value);
$var = shared_clone({'foo' => [qw/foo bar baz/]});
$hsh{'foo'} = $scalar_value;
$hsh{'bar'} = $shared_ref_value;
$hsh{'baz'} = shared_clone($non_shared_ref_value);
$hsh{'quz'} = shared_clone([1..3]);
$ary[0] = $scalar_value;
$ary[1] = $shared_ref_value;
$ary[2] = shared_clone($non_shared_ref_value);
$ary[3] = shared_clone([ {}, [] ]);
{ lock(%hash); ... }
cond_wait($scalar);
cond_timedwait($scalar, time() + 30);
cond_broadcast(@array);
cond_signal(%hash);
my $lockvar :shared;
# condition var != lock var
cond_wait($var, $lockvar);
cond_timedwait($var, time()+30, $lockvar);
like. everything you need is right there. π«Ά
π¦ DESCRIPTION π¦
okay so the tea: by default, variables are private to each thread, and every newly created thread gets its own private copy of every variable that already exists. that's just the default behaviour, it's giving "you can't sit with us" energy.
This module changes all that β it lets you share variables across different threads</> (and pseudo-forks on Win32 πͺ too). And it's meant to be used together with the threads module, like they're a duo, a package deal, main character and their bestie. π
Also, ngl, there's a limit and you need to know it: this module supports the sharing of these data types only:
- scalars and scalar refs
- arrays and array refs
- hashes and hash refs
that's the guest list. if it's not on it, it's not getting in. π
π EXPORT π
The following functions are exported by this module:
shareshared_cloneis_sharedcond_waitcond_timedwaitcond_signalandcond_broadcast
Now here's a lil plot twist that's actually iconic: if this module gets imported when threads has not yet been loaded, then all of those functions become no-ops. which sounds like a downgrade but is honestly a slay, because it makes it possible to write modules that work in both threaded and non-threaded environments. periodt. β¨
π FUNCTIONS π
π
share VARIABLE
share takes a variable and marks it as shared. look how easy:
my ($scalar, @array, %hash);
share($scalar);
share(@array);
share(%hash);
share will return the shared rvalue, but always as a reference. yes, always. that's just how it is. π
You can also mark a variable as shared at compile time by using the :shared attribute instead:
my ($var, %hash, @array) :shared;
Shared variables can only store scalars, refs of shared variables, or refs of shared data (and yes we're getting into that in the next section, hold on):
my ($var, %hash, @array) :shared;
my $bork;
# Storing scalars
$var = 1;
$hash{'foo'} = 'bar';
$array[0] = 1.5;
# Storing shared refs
$var = \%hash;
$hash{'ary'} = \@array;
$array[1] = \$var;
# The following are errors:
# $var = \$bork; # ref of non-shared variable
# $hash{'bork'} = []; # non-shared array ref
# push(@array, { 'x' => 1 }); # non-shared hash ref
ok bestie read those last three lines very carefully because they're literally the errors β that is NOT allowed, do not try it, the vibes will be rancid. π
π§ shared_clone REF
shared_clone takes a reference and returns a shared version of its argument, doing a deep copy on any non-shared elements. And any shared elements in the argument are used as is (i.e., they are not cloned). π«Ά
my $cpy = shared_clone({'foo' => [qw/foo bar baz/]});
Object status (i.e., the class an object is blessed into) is also cloned. yes, the whole aura comes with it:
my $obj = {'foo' => [qw/foo bar baz/]};
bless($obj, 'Foo');
my $cpy = shared_clone($obj);
print(ref($cpy), "\n"); # Outputs 'Foo'
For cloning empty array or hash refs, the following may also be used:
$var = &share([]); # Same as $var = shared_clone([]);
$var = &share({}); # Same as $var = shared_clone({});
Now, real talk: not all Perl data types can be cloned (e.g., globs, code refs). π By default, shared_clone will croak if it encounters such items. If you'd rather it just complain quietly instead of full-on crashing, then set the following:
$threads::shared::clone_warn = 1;
In this case, undef will be substituted for the item to be cloned. And if you set it to zero:
$threads::shared::clone_warn = 0;
then the undef substitution will be performed silently. no drama, no warning, just vibes. π€«
π is_shared VARIABLE
is_shared checks if the specified variable is shared or not. If it is shared, it returns the variable's internal ID (similar to refaddr() β see Scalar::Util). Otherwise, it returns undef. simple as that bestie.
if (is_shared($var)) {
print("\$var is shared\n");
} else {
print("\$var is not shared\n");
}
When used on an element of an array or hash, is_shared checks if the specified element belongs to a shared array or hash. (it does not check the contents of that element, okay, read it again, it does not.)
my %hash :shared;
if (is_shared(%hash)) {
print("\%hash is shared\n");
}
$hash{'elem'} = 1;
if (is_shared($hash{'elem'})) {
print("\$hash{'elem'} is in a shared hash\n");
}
π lock VARIABLE
lock places a advisory lock on a variable until the lock goes out of scope. If the variable is already locked by another thread, the lock call will block until it's available. and if the same thread calls lock multiple times from within dynamically nested scopes? totally safe β the variable stays locked until the outermost lock on it goes out of scope. π«Ά
lock follows references exactly one level:
my %hash :shared;
my $ref = \%hash;
lock($ref); # This is equivalent to lock(%hash)
note that you cannot explicitly unlock a variable; you can only wait for the lock to go out of scope. the easiest way to do that is to lock the variable inside a block. so like:
my $var :shared;
{
lock($var);
# $var is locked from here to the end of the block
...
}
# $var is now unlocked
As locks are advisory, they do not prevent data access or modification by another thread that doesn't itself attempt to obtain a lock on the variable. it's giving "rules for thee but not for me" honestly. π
Oh and also β you cannot lock the individual elements of a container variable:
my %hash :shared;
$hash{'foo'} = 'bar';
#lock($hash{'foo'}); # Error
lock(%hash); # Works
If you need more fine-grained control over shared variable access, see Thread::Semaphore. β¨
π cond_wait VARIABLE / cond_wait CONDVAR, LOCKVAR
The cond_wait function takes a locked variable as a parameter, unlocks the variable, and blocks until another thread does a cond_signal or cond_broadcast for that same locked variable. the variable that cond_wait blocked on is re-locked after the cond_wait is satisfied.
If there are multiple threads cond_waiting on the same variable, all but one will re-block waiting to reacquire the lock on the variable. (so if you're only using cond_wait for synchronization, give up the lock as soon as possible, bestie, don't hog it. π
)
Now here's the fine print: the two actions of unlocking the variable and entering the blocked wait state are atomic, but the two actions of exiting from the blocked wait state and re-locking the variable are not. remember that. π«Ά
In its second form, cond_wait takes a shared, unlocked variable followed by a shared, locked variable. The second variable is unlocked and thread execution suspended until another thread signals the first variable.
important, like actually important: the variable can be notified even if no thread did acond_signalorcond_broadcaston the variable!! π it is therefore important to check the value of the variable and go back to waiting if the requirement is not fulfilled. for example, to pause until a shared counter drops to zero:
{ lock($counter); cond_wait($counter) until $counter == 0; }
π cond_timedwait VARIABLE, ABS_TIMEOUT / cond_timedwait CONDVAR, ABS_TIMEOUT, LOCKVAR
In its two-argument form, cond_timedwait takes a locked variable and an absolute timeout in epoch seconds (see time() in perlfunc for more) as parameters, unlocks the variable, and blocks until the timeout is reached or another thread signals the variable.
A false value is returned if the timeout is reached, and a true value otherwise. In either case, the variable is re-locked upon return. π«Ά
Like cond_wait, this function may take a shared, locked variable as an additional parameter; in this case the first parameter is an unlocked condition variable protected by a distinct lock variable.
Again like cond_wait, waking up and reacquiring the lock are not atomic, and you should always check your desired condition after this function returns. but since the timeout is an absolute value, it does not have to be recalculated with each pass, which is lowkey genius:
lock($var);
my $abs = time() + 15;
until ($ok = desired_condition($var)) {
last if !cond_timedwait($var, $abs);
}
# we got it if $ok, otherwise we timed out!
β cond_signal VARIABLE
The cond_signal function takes a locked variable as a parameter and unblocks one thread that's cond_waiting on that variable. If more than one thread is blocked in a cond_wait on that variable, only one will be unblocked β and which one is indeterminate. mystery thread, we don't know her. π
If there are no threads blocked in a cond_wait on the variable, the signal is discarded. By always locking before signaling, you can (with care) avoid signaling before another thread has entered cond_wait(). π
cond_signal will normally generate a warning if you attempt to use it on an unlocked variable. On the rare occasions where doing this may be sensible, you can suppress the warning with:
{ no warnings 'threads'; cond_signal($foo); }
π¦ cond_broadcast VARIABLE
The cond_broadcast function works similarly to cond_signal. cond_broadcast, though, will unblock all the threads that are blocked in a cond_wait on the locked variable, rather than only one. it's giving "everybody gets a turn" energy and honestly? iconic. π
π OBJECTS π
okay so bestie, threads::shared ALSO exports its own little version of bless() β and this one gets shared objects, like it actually understands the assignment. when you bless a shared thing with it, the blessing propagates across threads. it's giving telepathy. it's giving glow-up that travels. β¨
watch this serve:
# Create a shared 'Foo' object
my $foo :shared = shared_clone({});
bless($foo, 'Foo');
# Create a shared 'Bar' object
my $bar :shared = shared_clone({});
bless($bar, 'Bar');
# Put 'bar' inside 'foo'
$foo->{'bar'} = $bar;
# Rebless the objects via a thread
threads->create(sub {
# Rebless the outer object
bless($foo, 'Yin');
# Cannot directly rebless the inner object
#bless($foo->{'bar'}, 'Yang');
# Retrieve and rebless the inner object
my $obj = $foo->{'bar'};
bless($obj, 'Yang');
$foo->{'bar'} = $obj;
})->join();
print(ref($foo), "\n"); # Prints 'Yin'
print(ref($foo->{'bar'}), "\n"); # Prints 'Yang'
print(ref($bar), "\n"); # Also prints 'Yang'
notice the sneaky little trick in there β you literally cannot directly rebless the inner object (#bless($foo->{'bar'}, 'Yang'); is commented out for a REASON, bestie), so you have to pull it out, bless it, and shove it back in. that's the whole ritual. π and yes, $bar also ends up printing 'Yang' because it's the same underlying shared thing. no cap. π
π§ NOTES π§
threads::shared is designed to silently disable itself if threads aren't available. yes, silently, like it's sneaking out of the party. π«₯ it just quietly stops doing anything.
why do we love that? because it means you can write modules and packages that work in BOTH threaded and non-threaded applications. one codebase, two vibes. iconic behavior.
but listen β if you actually want access to threads, you must use threads before you use threads::shared. order matters, bestie. and threads will emit a warning if you use it after threads::shared. it's not mad, it's just disappointed. π
β οΈ order yourusestatements:threadsfirst, thenthreads::shared. that's the vibe. fr fr.
π¨ WARNINGS π¨
these two are the warning messages you might get, and they both point to the same place:
cond_broadcast() called on unlocked variablecond_signal() called on unlocked variable
both of them: See "cond_signal VARIABLE", above. β like, go read that part, bestie, it's all explained up there. π₯
π BUGS AND LIMITATIONS π
okay this is the section where we hold hands and get real. grab a snack. π
the share() data loss situation
when "share" is used on arrays, hashes, array refs or hash refs β any data they contain will be lost. gone. evaporated. π
my @arr = qw(foo bar baz);
share(@arr);
# @arr is now empty (i.e., == ());
# Create a 'foo' object
my $foo = { 'data' => 99 };
bless($foo, 'foo');
# Share the object
share($foo); # Contents are now wiped out
print("ERROR: \$foo is empty\n")
if (! exists($foo->{'data'}));
so yeah. the contents get wiped. that print will absolutely fire. π
therefore: populate such variables AFTER declaring them as shared. that's the move.
good news tho: scalar and scalar refs are not affected by this problem. they're built different. π
the nesting bless situation
blessing a shared item after it's already been nested inside another shared item does not propagate the blessing to the shared reference:
my $foo = &share({});
my $bar = &share({});
$bar->{foo} = $foo;
bless($foo, 'baz'); # $foo is now of class 'baz',
# but $bar->{foo} is unblessed.
read that comment again. $foo is class 'baz', but $bar->{foo}?? unblessed. rude.
therefore: bless objects BEFORE sharing them. do it in the right order, like putting on socks before shoes. π§¦π
the "should you even share this object" situation
it is often not wise to share an object unless the class itself has been written to support sharing. big deal, honestly.
for example:
- a shared object's destructor may get called multiple times β once for each thread's scope exit π΅
- or it may not get called at all if it's embedded inside another shared object π
- and another issue: the contents of hash-based objects will be lost because of that limitation we just talked about above
if you want to see how to make a class that actually supports object sharing, go look at examples/class.pl β it's in the CPAN distribution of this module. go, bestie, it's homework. π
the destructor situation
destructors may not be called on objects if those objects still exist at global destruction time.
so if the destructors must be called β and listen, sometimes they must β make sure:
- there are no circular references, and
- nothing is referencing the objects before the program ends
that's it. that's the whole checklist. don't leave loose threads. (pun fully intended π)
arrays and autovivification, or: the "no" list
- does NOT support
"splice"on arrays - does NOT support explicitly changing array lengths via
$#arrayβ use"push"and"pop"instead
and ALSO:
- taking references to the elements of shared arrays and hashes does not autovivify the elements
- slicing a shared array/hash over non-existent indices/keys does not autovivify the elements either
nothing autovivifies. it's giving "you get what you asked for and not one crumb more." π
the silly little share() trap
share() lets you do share($hashref->{key}) and share($arrayref->[idx]) without giving any error message. sneaky, right? π
BUT β the "$hashref->{key}" or "$arrayref->[idx]" is not shared. which means when you try to lock($hashref->{key}) or lock($arrayref->[idx]) in another thread, you get this error:
lock can only be used on shared values
so it looks fine. it sounds fine. it is NOT fine. trap detected. π©
refaddr() is not the girl you think she is
using refaddr() is unreliable for testing whether or not two shared references are equivalent (for example, when you're testing for circular references). use is_shared() instead:
use threads;
use threads::shared;
use Scalar::Util qw(refaddr);
# If ref is shared, use threads::shared's internal ID.
# Otherwise, use refaddr().
my $addr1 = is_shared($ref1) || refaddr($ref1);
my $addr2 = is_shared($ref2) || refaddr($ref2);
if ($addr1 == $addr2) {
# The refs are equivalent
}
see how cute that is? if the ref is shared, use threads::shared's own internal ID. otherwise, fall back to refaddr(). best of both worlds, no lies. β¨
each() being messy
each() does not work properly on shared references embedded in shared structures. for example, this:
my %foo :shared;
$foo{'bar'} = shared_clone({'a'=>'x', 'b'=>'y', 'c'=>'z'});
while (my ($key, $val) = each(%{$foo{'bar'}})) {
...
}
yeah, that's a no. π¬ instead, either of the following will work:
my $ref = $foo{'bar'};
while (my ($key, $val) = each(%{$ref})) {
...
}
foreach my $key (keys(%{$foo{'bar'}})) {
my $val = $foo{'bar'}{$key};
...
}
pick your fighter. both slay. both work. π«Ά
dualvar() and the $! situation
this module supports dual-valued variables created using dualvar() from Scalar::Util. π
HOWEVER β and this is the plot twist β while $! acts like a dualvar, it's implemented as a tied SV. so to propagate its value, use the follow construct, if needed:
my $errno :shared = dualvar($!,$!);
noted? noted. π
bug reports, bestie
view existing bug reports at β and submit any new bugs, problems, patches, etc. to:
<http://rt.cpan.org/Public/Dist/Display.html?Name=threads-shared>
they want your feedback. it's giving community. it's giving open source. ποΈβ¨
π SEE ALSO π
threads::sharedon MetaCPAN:<https://metacpan.org/release/threads-shared>- code repository for CPAN distribution:
<https://github.com/Dual-Life/threads-shared> threads,perlthrtut<http://www.perl.com/pub/a/2002/06/11/threads.html>and<http://www.perl.com/pub/a/2002/09/04/threads.html>- Perl threads mailing list:
<http://lists.perl.org/list/ithreads.html> - sample code in the
examplesdirectory of this distribution on CPAN
go read all of it. iykyk. ππ
π AUTHOR π
Artur Bergman <sky AT crucially DOT net> β the original main character. β¨
Documentation borrowed from the old Thread.pm. (recycling is iconic, honestly π±)
CPAN version produced by Jerry D. Hedden <jdhedden AT cpan DOT org>. π«Ά
π LICENSE π
threads::shared is released under the same license as Perl. periodt. π
okay that's the whole page bestie, you made it to the end and i'm so proud of you π₯Ή this was threads::shared(3perl) from perl v5.44.0, dated 2026-10-17 β love that for us. now go forth and share your variables responsibly. no cap. πβ¨π¦
π¦ where this page comes from
- arch rolling: perl 5.44.0-1 Β· Artistic-1.0-Perl AND GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms