NAME

forks::shared - drop-in replacement for Perl threads::shared with forks()

SYNOPSIS

use forks;
use forks::shared;

my $variable : shared;
my @array    : shared;
my %hash     : shared;

share( $variable );
share( @array );
share( %hash );

lock( $variable );
cond_wait( $variable );
cond_wait( $variable, $lock_variable );
cond_timedwait( $variable, abs time );
cond_timedwait( $variable, abs time, $lock_variable );
cond_signal( $variable );
cond_broadcast( $variable );

bless( $variable, class name );

# Enable deadlock detection and resolution
use forks::shared deadlock => {
  detect => 1,
  resolve => 1
);
# or
threads::shared->set_deadlock_option(
  detect  => 1,
  resolve => 1
);

DESCRIPTION

The forks::shared pragma allows a developer to use shared variables with threads (implemented with the "forks" pragma) without having to have a threaded perl, or to even run 5.8.0 or higher.

forks::shared is currently API compatible with CPAN threads::shared version 1.05.

EXPORT

share, cond_wait, cond_timedwait, cond_signal, cond_broadcast, is_shared, bless

See "EXPORT" in threads::shared for more information.

OBJECTS

forks::shared exports a versio of bless() that works on shared objects, such that blessings propagate across threads. See threads::shared for usage information and the forks test suite for additional examples.

EXTRA FEATURES

Deadlock detection and resolution

In the interest of helping programmers debug one of the most common bugs in threaded application software, forks::shared supports a full deadlock detection and resolution engine.

Automated detection and resolution

There are two ways to enable these features: either at import time in a use statement, such as:

use forks::shared deadlock => { OPTIONS }

or during runtime as a class method call to set_deadlock_option, like:

forks::shared->set_deadlock_option( OPTIONS );
#or
threads::shared->set_deadlock_option( OPTIONS );

where OPTIONS may be a combination of any of the following:

detect         => 1 (enable) or 0 (disable)
period         => number of seconds between asynchronous polls
resolve        => 1 (enable) or 0 (disable)
resolve_signal => any supported POSIX signal

The detect option enables deadlock detection. By itself, this option enabled synchronous deadlock detection, which efficiently checks for potential deadlocks at lock() time. If any are detected and warnings are enabled, it will print out details to STDERR like the following example:

Deadlock detected:
    TID   SV LOCKED   SV LOCKING   Caller
      1           3            4   t/forks06.t at line 41
      2           4            3   t/forks06.t at line 46

The period option, if set to a value greater than zero, is the number of seconds between asynchronous deadlock detection checks. Asynchronous detection is useful for debugging rare, time-critical race conditions leading to deadlocks that may be masked by the slight time overhead introduced by synchronous detection on each lock() call. Overall, it is less CPU intensive than synchronous deadlock detection.

The resolve option enables auto-termination of one thread in each deadlocked thread pair that has been detected. As with the detect option, resolve prints out the action it performs to STDERR, if warnings are enabled. NOTE: By default, resolve uses SIGKILL to break deadlocks, so this feature should not be used in environments where stability of the rest of your application may be adversely affected by process death in this manner.

The resolve_signal option allows modification of the signal used by resolve. This may be useful if you wish to override a signal in your threads to close sensitive resources or print out additional debugging information before exit. Signals may be any trappable ones given by number, as defined by POSIX ":signal_h" export, or the name of the signal, such as 'TERM' and 'USR1', or 'SIGTERM' and 'SIGUSR1'.

For example:

use forks;
use POSIX ':signal_h';
use forks::shared
    deadlock => {detect=> 1, resolve => 1, resolve_signal => SIGTERM};
use Carp 'cluck'
$SIG{TERM} = sub{ cluck "Caught TERM signal"; CORE::exit(); };

Manual detection

If you wish to check for deadlocks without enabling automated deadlock detection, forks provides an additonal thread object method,

$thr->is_deadlocked()

that reports whether the thread in question is currently deadlocked. This method may be used in conjunction with the resolve deadlock option to auto-terminate offending threads.

Splice on shared array

As of at least threads::shared 1.05, the splice function has not been implememted for arrays; however, forks::shared fully supports splice on shared arrays.

share() doesn't lose value for arrays and hashes

In the standard Perl threads implementation, arrays and hashes are re-initialized when they become shared (with the share()) function. The share() function of forks::shared does not initialize arrays and hashes when they become shared with the share() function.

This could be considered a bug in the standard Perl implementation. In any case this is an inconsistency of the behaviour of threads.pm and forks.pm. Maybe a special "totheletter" option should be added to forks.pm to make forks.pm follow this behaviour of threads.pm to the letter.

NOTE: If you do not have a natively threaded perl and you have installed and are using forks in "threads.pm" override mode (where "use threads" loads forks.pm), then this module will explicitly emulate the behavior of standard threads::shared and lose value for arrays and hashes with share(). Additionally, array splice function will become a no-op with a warning.

CAVIATS

These problems are known and will be fixed in the future:

test-suite exits in a weird way

Although there are no errors in the test-suite, the test harness sometimes thinks there is something wrong because of an unexpected exit() value. This is an issue with Test::More's END block, which wasn't designed to co-exist with a threads environment and forked processes. Hopefully, that module will be patched in the future, but for now, the warnings are harmless and may be safely ignored.

shared variable in push() on shared array bombs

For some reason, using a bare shared variable as a parameter in a push() on a shared array, bombs. This can be fixed by adding .'' to the shared variable.

push( @shared,$shared );    # bombs
push( @shared,$shared.'' ); # works

This could be a generic problem with tie() in Perl, judging from some very recent discussion on p5p.

CREDITS

threads::shared

For some of the XS code used for forks::shared exported bless function.

CURRENT MAINTAINER

Eric Rybski <rybskej@yahoo.com>.

ORIGINAL AUTHOR

Elizabeth Mattijsen, <liz@dijkmat.nl>.

COPYRIGHT

Copyright (c) 2005-2006 Eric Rybski <rybskej@yahoo.com>, 2002-2004 Elizabeth Mattijsen <liz@dijkmat.nl>. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

threads::shared, forks, forks::BerkeleyDB::shared.