views:

387

answers:

3

Hi, I am using .NET to create an artificial life program and I am using C#'s pseudo random class defined in a Singleton. The idea is that if I use the same random number generator throughout the application, I could merely save the seed and then reload from the seed to recompute a certain interesting run.

public sealed class RandomNumberGenerator : Random
{
    private static readonly RandomNumberGenerator instance = new RandomNumberGenerator();

    RandomNumberGenerator()
    {

    }

    public static RandomNumberGenerator Instance
    {
        get
        {
            return instance;
        }
    }
}

I also wanted a method that could give me two different random numbers.

public static Tuple<int, int> TwoDifferentRandomNumbers(this Random rnd, int minValue, int maxValue)
    {
        if (minValue >= maxValue)
            throw new ArgumentOutOfRangeException("maxValue", "maxValue must be greater than minValue");
        if (minValue + 1 == maxValue)
            return Tuple.Create<int, int>(minValue, maxValue);

        int rnd1 = rnd.Next(minValue, maxValue);
        int rnd2 = rnd.Next(minValue, maxValue);
        while (rnd1 == rnd2)
        {                
            rnd2 = rnd.Next(minValue, maxValue);
        }
        return Tuple.Create<int, int>(rnd1, rnd2);            
    }

The problem is that sometimes rnd.Next(minValue,maxValuealways returns minValue. If I breakpoint at this point and try creating a double and setting it to rnd.NextDouble(), it returns 0.0. Anyone know why this is happening?

I know that it is a pseudo random number generator, but frankly, I hadn't expected it to lock at 0. The random number generator is being accessed from multiple threads... could this be the source of the problem?

EDIT : Thanks, the problem ended up being thread safety.

This is the new version of the class.

 public sealed class RandomNumberGenerator : Random
{
    private static Random _global = new Random();
    [ThreadStatic]
    private static Random _localInstance;

    RandomNumberGenerator()
    {

    }

    public static Random Instance
    {
        get
        {
            Random inst = _localInstance;
            if (inst == null)
            {
                int seed;
                lock (_global) seed = _global.Next();
                _localInstance = inst = new Random(seed);
            }
            return _localInstance;
        }
    }
}
+6  A: 

The Random class is not thread-safe.

You should make your static instance [ThreadStatic], or protect it with a lock.

SLaks
+1  A: 

The idea is that if I use the same random number generator throughout the application, I could merely save the seed and then reload from the seed to recompute a certain interesting run.

You don't actually need a singleton instance of the RNG for this. If you initialize two separate instances of Random to the same seed, they will produce exactly the same sequence.

My advice is, save the seed, but get rid of the singleton.

Aaronaught
+3  A: 

If you use only One RNG for multiple threads even if you save the seed, you won't be able to generate the same numbers the next time you launch your application because you won't be sure that the calls to the RNG from the different threads will be in the same order.

If you have a fixed/known number of thread make a RNG per Thread and save each seed.

Forget what I just said if you're 100% sure that each thread will call the RNG with exactly the same order as the last time if you use the same seed.

Jipy
whoops, I'd left this post answer window open a bit too long, +1... this is exactly what I wanted to say!
Eamon Nerbonne
Thanks, you were exactly right. I accepted your comment as answer to give you some more karma :P Also, thanks for telling me about the other multiple-thread issue, it hadn't quite crossed my mind!
Jean Azzopardi