Skip to content

Commit

Permalink
Revert back to calling CORE::rand
Browse files Browse the repository at this point in the history
1. Revert back to calling CORE::rand() to set the internal seed. MCE and MCE::Child cannot assume the srand or setter function used by the application for predictability.

2. Add class methods MCE->seed and MCE::Child->seed to retrieve the seed.
  • Loading branch information
marioroy committed Jun 10, 2024
1 parent 5d561ca commit 318306e
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 48 deletions.
35 changes: 7 additions & 28 deletions lib/MCE.pm
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ BEGIN {
return $self->{$_p};
};
}
for my $_p (qw( chunk_id task_id task_wid wid )) {
for my $_p (qw( chunk_id seed task_id task_wid wid )) {
*{ $_p } = sub () {
my $self = shift; $self = $MCE unless ref($self);
return $self->{"_${_p}"};
Expand Down Expand Up @@ -641,25 +641,7 @@ sub spawn {
for (0 .. $_max_workers - 1);
}

# The PDL module 2.062 ~ 2.089 exports its own srand() function, that
# silently clobbers Perl's srand function, and does not seed Perl's
# pseudo-random generator. https://perlmonks.org/?node_id=11159773

if ( $INC{'PDL/Primitive.pm'} ) {
# Call PDL's random() function if exported i.e. use PDL.

my $caller = caller(); local $@;
$caller = caller(1) if ( $caller =~ /^MCE/ );
$caller = caller(2) if ( $caller =~ /^MCE/ );
$caller = caller(3) if ( $caller =~ /^MCE/ );

$self->{_seed} = eval "$caller->can('random')"
? int(PDL::Primitive::random() * 1e9)
: int(CORE::rand() * 1e9);
}
else {
$self->{_seed} = int(CORE::rand() * 1e9);
}
$self->{_seed} = int(CORE::rand() * 1e9);

## -------------------------------------------------------------------------

Expand Down Expand Up @@ -1609,8 +1591,7 @@ sub sess_dir {
return $self->{_sess_dir} if defined $self->{_sess_dir};

if ($self->{_wid} == 0) {
$self->{_sess_dir} = $self->{_spawned}
? _make_sessdir($self) : undef;
$self->{_sess_dir} = $self->{_spawned} ? _make_sessdir($self) : undef;
}
else {
my $_chn = $self->{_chn};
Expand Down Expand Up @@ -2033,17 +2014,15 @@ sub _dispatch {
MCE::Hobo->_clear() if $INC{'MCE/Hobo.pm'};
}

# Sets the seed of the base generator uniquely between workers.
# Set the seed of the base generator uniquely between workers.
# The new seed is computed using the current seed and ID value.
# One may set the seed at the application level for predictable
# results (non-thread workers only). Ditto for Math::Prime::Util,
# Math::Random, Math::Random::MT::Auto, and PDL.
#
# MCE 1.892, 2024-06-08
# Removed check if spawning threads i.e. use_threads.
# Predictable output matches non-threads for CORE,
# Math::Prime::Util, and Math::Random::MT::Auto.
# https://perlmonks.org/?node_id=11159834
# MCE 1.892, 2024-06-08: Enable predictability running threads.
# Output matches non-threads for CORE, Math::Prime::Util, and
# Math::Random::MT::Auto. https://perlmonks.org/?node_id=11159834

{
my $_wid = $_args[1];
Expand Down
36 changes: 16 additions & 20 deletions lib/MCE/Child.pm
Original file line number Diff line number Diff line change
Expand Up @@ -111,25 +111,7 @@ sub init {
$_DATA->{ $pkg } = MCE::Child::_hash->new( $chnl );
$_DATA->{"$pkg:id"} = 0;

# The PDL module 2.062 ~ 2.089 exports its own srand() function, that
# silently clobbers Perl's srand function, and does not seed Perl's
# pseudo-random generator. https://perlmonks.org/?node_id=11159773

if ( $INC{'PDL/Primitive.pm'} ) {
# Call PDL's random() function if exported i.e. use PDL.

my $caller = caller(); local $@;
$caller = caller(1) if ( $caller =~ /^MCE/ );
$caller = caller(2) if ( $caller =~ /^MCE/ );
$caller = caller(3) if ( $caller =~ /^MCE/ );

$_DATA->{"$pkg:seed"} = eval "$caller->can('random')"
? int(PDL::Primitive::random() * 1e9)
: int(CORE::rand() * 1e9);
}
else {
$_DATA->{"$pkg:seed"} = int(CORE::rand() * 1e9);
}
$_DATA->{"$pkg:seed"} = int(CORE::rand() * 1e9);

$MCE::_GMUTEX->unlock() if ( $_tid && $MCE::_GMUTEX );
}
Expand Down Expand Up @@ -264,7 +246,7 @@ sub create {
MCE::Child->_clear() if $INC{'MCE/Child.pm'};
MCE::Hobo->_clear() if $INC{'MCE/Hobo.pm'};

# Sets the seed of the base generator uniquely between workers.
# Set the seed of the base generator uniquely between workers.
# The new seed is computed using the current seed and ID value.
# One may set the seed at the application level for predictable
# results. Ditto for PDL, Math::Prime::Util, Math::Random, and
Expand Down Expand Up @@ -559,6 +541,13 @@ sub result {
wantarray ? @{ delete $self->{RESULT} } : delete( $self->{RESULT} )->[-1];
}

sub seed {
_croak('Usage: MCE::Child->seed()') if ref($_[0]);
my $pkg = exists $_SELF->{PKG} ? $_SELF->{PKG} : "$$.$_tid.".caller();

return $_DATA->{"$pkg:seed"};
}

sub self {
ref($_[0]) ? $_[0] : $_SELF;
}
Expand Down Expand Up @@ -1543,6 +1532,13 @@ C<wantarray> aware.
my @res2 = $child2->result(); # ( foo )
my $res2 = $child2->result(); # foo
=item MCE::Child->seed()
Class method that returns the internal random generated seed or undefined.
The seed is generated once during init or initial create.
Current API available since 1.895.
=item MCE::Child->self()
Class method that allows a child to obtain it's own I<MCE::Child> object.
Expand Down
9 changes: 9 additions & 0 deletions lib/MCE/Core.pod
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,15 @@ Sending to C<IO::All> { File, Pipe, STDIO } is supported since MCE 1.845.
MCE->say($out, "sent to stdout");
MCE->say($err, "sent to stderr");

=head2 MCE->seed ( void )

=head2 $mce->seed ( void )

Returns the internal random generated seed or undefined.
The seed is generated each time, prior to spawning a MCE session.

Current API available since 1.895.

=head2 MCE->sess_dir ( void )

=head2 $mce->sess_dir ( void )
Expand Down
4 changes: 4 additions & 0 deletions lib/MCE/Subs.pm
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ sub mce_chunk_size ( ) { return $MCE::MCE->chunk_size(); }
sub mce_max_retries ( ) { return $MCE::MCE->max_retries(); }
sub mce_max_workers ( ) { return $MCE::MCE->max_workers(); }
sub mce_pid ( ) { return $MCE::MCE->pid(); }
sub mce_seed ( ) { return $MCE::MCE->seed(); }
sub mce_sess_dir ( ) { return $MCE::MCE->sess_dir(); }
sub mce_task_id ( ) { return $MCE::MCE->task_id(); }
sub mce_task_name ( ) { return $MCE::MCE->task_name(); }
Expand Down Expand Up @@ -176,6 +177,7 @@ sub _export_subs {
*{ $_package . '::mce_max_retries' } = \&mce_max_retries;
*{ $_package . '::mce_max_workers' } = \&mce_max_workers;
*{ $_package . '::mce_pid' } = \&mce_pid;
*{ $_package . '::mce_seed' } = \&mce_seed;
*{ $_package . '::mce_sess_dir' } = \&mce_sess_dir;
*{ $_package . '::mce_task_id' } = \&mce_task_id;
*{ $_package . '::mce_task_name' } = \&mce_task_name;
Expand Down Expand Up @@ -371,6 +373,8 @@ MCE methods are described in L<MCE::Core>.
=item * mce_pid
=item * mce_seed
=item * mce_sess_dir
=item * mce_task_id
Expand Down

0 comments on commit 318306e

Please sign in to comment.