digmon has asked for the wisdom of the Perl Monks concerning the following question:

I have an issue with rand() while fork()ing and using IO::Socket::SSL.

In all forked processes rand() gives me the same set of random numbers. If I call rand() several times I get random numbers as expected, but in all forked processes I get the same random set.

If I remove IO::Socket::SSL the set is random in all processes.

I've reduced the case down to this:

use strict; use IO::Socket::SSL; foreach (1 .. 5) { my $pid = fork(); next if $pid; random(); random(); exit; } sub random { print sprintf("Process %d: %d", $$, int(rand(100000))), "\n"; }

If I run the script I get this output:

$ perl fork_rand.pl Process 13788: 32768 Process 13788: 3778 Process 13789: 32768 Process 13789: 3778 Process 13790: 32768 Process 13790: 3778 Process 13791: 32768 Process 13791: 3778 Process 13792: 32768 Process 13792: 3778

I would expect the numbers to be random in all processes -- not return the same set of numbers.

If I remove IO::Socket::SSL everything works as expected:

$ perl fork_rand.pl Process 13806: 94050 Process 13806: 14790 Process 13807: 89099 Process 13807: 93200 Process 13808: 48447 Process 13808: 14001 Process 13809: 28378 Process 13809: 71603 Process 13810: 44245 Process 13810: 86800

Is this a known bug?

I've tested on both Linux and FreeBSD, with latest version of IO::Socket::SSL and Perl 5.8.8.

Replies are listed 'Best First'.
Re: fork(), IO::Socket::SSL and rand()
by Fletch (Bishop) on Nov 19, 2008 at 15:14 UTC

    My guess is that something in IO::Socket::SSL is triggering a call to srand in the parent before any of the children are forked so they all are starting from the same seed (since it's already been called once the children don't call it again when the first rand call is made). If you called srand after your fork in each child you'd see random-er results I'd bet.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: fork(), IO::Socket::SSL and rand()
by ccn (Vicar) on Nov 19, 2008 at 15:21 UTC

    It is not issue of IO::Socket::SSL. If you call rand once before the fork loop you get the same results. It is because of rand seed initialized before forking

Re: fork(), IO::Socket::SSL and rand()
by Anonymous Monk on Nov 19, 2008 at 15:16 UTC
    Instead of use, try require IO::Socket::SSL; after fork
Re: fork(), IO::Socket::SSL and rand()
by digmon (Initiate) on Nov 19, 2008 at 15:46 UTC

    Thank you all. :-)

    As you predicted, srand() certainly solved the problem.

      It appears that you misunderstood. My fellow monks didn't say that calling srand is the solution. They said that calling srand is the problem.

      Now, you could call srand in the children. But that's not a very good solution, since your seed is probably not going to be as good as Perl's. Ideally, what you want to do is delay srand getting called until after you've forked by avoiding calls to rand until after you've forked.

      Since IO::Socket::SSL apparently calls rand on load, you need to delay its loading.

      use strict; foreach (1 .. 5) { my $pid = fork(); next if $pid; require IO::Socket::SSL; <--- random(); random(); exit; } sub random { print sprintf("Process %d: %d", $$, int(rand(100000))), "\n"; }

        Just feeling that somehow ikegami's answer could be better phrased:

        There are three points:

      • (added by me) calling srand() implicitly or explicitly with no seed should seed the way perl seeds (at least as the doc says for a perl version superior to 5.004)
      • then 'perldoc -f srand' says explicitly that one should not call srand() twice as you would lose randomness, so it seems that reseeding in each child is not the better option (one implicit call from use IO::Socket::SSL and one explicit call from each child)
      • finally actually delaying the implicit and only call to srand() can be done requiring IO::Socket::SSL in each child </it>

        IMHO this was the point made by fletch and at least another monk.

        cheers --stephan update: sorry not second post just answer