-
package threads::shared;
+use 5.007_003;
use strict;
use warnings;
-use Config;
-use Scalar::Util qw(weaken);
-use attributes qw(reftype);
-
BEGIN {
- if($Config{'useithreads'} && $Config::threads) {
- *share = \&share_enabled;
+ require Exporter;
+ our @ISA = qw(Exporter);
+ our @EXPORT = qw(share cond_wait cond_broadcast cond_signal);
+ our $VERSION = '0.90';
+
+ if ($threads::threads) {
+ *cond_wait = \&cond_wait_enabled;
+ *cond_signal = \&cond_signal_enabled;
+ *cond_broadcast = \&cond_broadcast_enabled;
+ require XSLoader;
+ XSLoader::load('threads::shared',$VERSION);
+ push @EXPORT,'bless';
+ }
+ else {
+ *share = \&share_disabled;
*cond_wait = \&cond_wait_disabled;
*cond_signal = \&cond_signal_disabled;
*cond_broadcast = \&cond_broadcast_disabled;
- *unlock = \&unlock_disabled;
- *lock = \&lock_disabled;
- } else {
- *share = \&share_enabled;
}
}
-require Exporter;
-require DynaLoader;
-our @ISA = qw(Exporter DynaLoader);
-
-our @EXPORT = qw(share cond_wait cond_broadcast cond_signal unlock lock);
-our $VERSION = '0.01';
-
-our %shared;
-
-
-sub cond_wait_disabled { return @_ };
-sub cond_signal_disabled { return @_};
-sub cond_broadcast_disabled { return @_};
-sub unlock_disabled { 1 };
-sub lock_disabled { 1 }
-sub share_disabled { return @_}
-
-sub share_enabled (\[$@%]) { # \]
- my $value = $_[0];
- my $ref = reftype($value);
- if($ref eq 'SCALAR') {
- my $obj = \threads::shared::sv->new($$value);
- bless $obj, 'threads::shared::sv';
- $shared{$$obj} = $value;
- weaken($shared{$$obj});
- } else {
- die "You cannot share ref of type $_[0]\n";
- }
-}
-sub CLONE {
- return unless($_[0] eq "threads::shared");
- foreach my $ptr (keys %shared) {
- if($ptr) {
- thrcnt_inc($shared{$ptr});
- }
- }
-}
+sub cond_wait_disabled (\[$@%]) { undef }
+sub cond_signal_disabled (\[$@%]) { undef }
+sub cond_broadcast_disabled (\[$@%]) { undef }
+sub share_disabled (\[$@%]) { return $_[0] }
+$threads::shared::threads_shared = 1;
-package threads::shared::sv;
-use base 'threads::shared';
-package threads::shared::av;
-use base 'threads::shared';
-
-package threads::shared::hv;
-use base 'threads::shared';
-
-
-bootstrap threads::shared $VERSION;
+sub threads::shared::tie::SPLICE
+{
+ die "Splice not implemented for shared arrays";
+}
__END__
=head1 SYNOPSIS
+ use threads;
use threads::shared;
- my($foo, @foo, %foo);
- share(\$foo);
- share(\@foo);
- share(\%hash);
- my $bar = share([]);
- $hash{bar} = share({});
+ my $var : shared;
+
+ my($scalar, @array, %hash);
+ share($scalar);
+ share(@array);
+ share(%hash);
+ my $bar = &share([]);
+ $hash{bar} = &share({});
+
+ { lock(%hash); ... }
- lock(\%hash);
- unlock(\%hash);
cond_wait($scalar);
- cond_broadcast(\@array);
- cond_signal($scalar);
+ cond_broadcast(@array);
+ cond_signal(%hash);
=head1 DESCRIPTION
- This modules allows you to share() variables. These variables will then be shared across different threads (and pseudoforks on win32). They are used together with the threads module.
+By default, variables are private to each thread, and each newly created
+thread gets a private copy of each existing variable. This module allows
+you to share variables across different threads (and pseudoforks on Win32).
+It is used together with the threads module.
+
+=head1 EXPORT
+
+C<share>, C<cond_wait>, C<cond_signal>, C<cond_broadcast>
+
+Note that if this module is imported when C<threads> has not yet been
+loaded, then these functions all become no-ops. This makes it possible
+to write modules that will work in both threaded and non-threaded
+environments.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item share VARIABLE
+
+C<share> takes a value and marks it as shared. You can share a scalar,
+array, hash, scalar ref, array ref or hash ref. C<share> will return
+the shared rvalue but always as a reference.
+
+C<share> will traverse up references exactly I<one> level.
+C<share(\$a)> is equivalent to C<share($a)>, while C<share(\\$a)> is not.
+
+A variable can also be marked as shared at compile time by using the
+C<shared> attribute: C<my $var : shared>.
+
+If you want to share a newly created reference unfortunately you
+need to use C<&share([])> and C<&share({})> syntax due to problems
+with Perl's prototyping.
-=head2 EXPORT
+=item lock VARIABLE
-share(), lock(), unlock(), cond_wait, cond_signal, cond_broadcast
+C<lock> places a lock on a variable until the lock goes out of scope.
+If the variable is locked by another thread, the C<lock> call will
+block until it's available. C<lock> is recursive, so multiple calls
+to C<lock> are safe -- the variable will remain locked until the
+outermost lock on the variable goes out of scope.
+
+If a container object, such as a hash or array, is locked, all the
+elements of that container are not locked. For example, if a thread
+does a C<lock @a>, any other thread doing a C<lock($a[12])> won't block.
+
+C<lock> will traverse up references exactly I<one> level.
+C<lock(\$a)> is equivalent to C<lock($a)>, while C<lock(\\$a)> is not.
+
+Note that you cannot explicitly unlock a variable; you can only wait
+for the lock to go out of scope. If you need more fine-grained
+control, see L<Thread::Semaphore>.
+
+=item cond_wait VARIABLE
+
+The C<cond_wait> function takes a B<locked> variable as a parameter,
+unlocks the variable, and blocks until another thread does a
+C<cond_signal> or C<cond_broadcast> for that same locked variable.
+The variable that C<cond_wait> blocked on is relocked after the
+C<cond_wait> is satisfied. If there are multiple threads
+C<cond_wait>ing on the same variable, all but one will reblock waiting
+to reacquire the lock on the variable. (So if you're only using
+C<cond_wait> for synchronisation, give up the lock as soon as
+possible). The two actions of unlocking the variable and entering the
+blocked wait state are atomic, The two actions of exiting from the
+blocked wait state and relocking the variable are not.
+
+It is important to note that the variable can be notified even if
+no thread C<cond_signal> or C<cond_broadcast> on the variable.
+It is therefore important to check the value of the variable and
+go back to waiting if the requirement is not fulfilled.
+
+=item cond_signal VARIABLE
+
+The C<cond_signal> function takes a B<locked> variable as a parameter
+and unblocks one thread that's C<cond_wait>ing on that variable. If
+more than one thread is blocked in a C<cond_wait> on that variable,
+only one (and which one is indeterminate) will be unblocked.
+
+If there are no threads blocked in a C<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().
+
+C<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 skip the warning with
+
+ { no warnings 'threads'; cond_signal($foo) }
+
+=item cond_broadcast VARIABLE
+
+The C<cond_broadcast> function works similarly to C<cond_signal>.
+C<cond_broadcast>, though, will unblock B<all> the threads that are
+blocked in a C<cond_wait> on the locked variable, rather than only one.
+
+=back
+
+=head1 NOTES
+
+threads::shared is designed to disable itself silently if threads are
+not available. If you want access to threads, you must C<use threads>
+before you C<use threads::shared>. threads will emit a warning if you
+use it after threads::shared.
=head1 BUGS
-Not stress tested!
-Does not support references
+C<bless> is not supported on shared references. In the current version,
+C<bless> will only bless the thread local reference and the blessing
+will not propagate to the other threads. This is expected to be
+implemented in a future version of Perl.
+
Does not support splice on arrays!
-The exported functions need a reference due to unsufficent prototyping!
+
+Taking references to the elements of shared arrays and hashes does not
+autovivify the elements, and neither does slicing a shared array/hash
+over non-existent indices/keys autovivify the elements.
+
+share() allows you to C<< share $hashref->{key} >> without giving any error
+message. But the C<< $hashref->{key} >> is B<not> shared, causing the error
+"locking can only be used on shared values" to occur when you attempt to
+C<< lock $hasref->{key} >>.
=head1 AUTHOR
-Artur Bergman <lt>artur at contiller.se<gt>
+Arthur Bergman E<lt>arthur at contiller.seE<gt>
+
+threads::shared is released under the same license as Perl
-threads is released under the same license as Perl
+Documentation borrowed from the old Thread.pm
=head1 SEE ALSO
-L<perl> L<threads>
+L<threads>, L<perlthrtut>, L<http://www.perl.com/pub/a/2002/06/11/threads.html>
=cut
-
-