How random is Random?

One of the issues I've come across in recent coding is trying to use Random in separate threads across a program.  The problem with this is that when you call the default constructor of Random it internally uses the current system time (Environment.TickCount at point of writing) as the seed.  As such this relies heavily on the resolution of the system timer.  In short the less granular the system timer the more likely you are to see collisions.  Obviously if you're calling this from multiple threads then the chances of collisions are far greater.  When you do see a collision the new Random().Next() suddenly isn't so random anymore!  For those of you not familiar with the idea of random number generators the basic rule is that if you feed the same seed into the generator then you will see the same sequence of numbers returned every time you call Next().  This is because the generators just use a complex mathematical formula under the hood to give the appearance of randomness and obviously if you feed the same number into a mathematical formula it will give you the same number out every time and therein lies the problem.  This means that every time you get a collision you'll see the same numbers appear from your supposedly Random number generator.  There are a few different potential solutions to this.  One is to make sure that you have a shared Random instance where the access is protected by a lock.

    public static class RandomNumber
    {
        private static Random _random = new Random();

        public static int Next()
        {
            lock (_random)
            {
                return _random.Next();
            }
        }
    }

The benefit of this is that it's a fairly simple solution.  Obviously you do have the cost of the expensive lock on every access though.  Another option is to use one Random instance per thread using a shared instance of Random for the seed generation for these new instances with similar locking code around the seed generation.  Depending on your particular use case you may of course be able to create your own seed generator which could be random enough in your case to guarantee uniqueness during runs of the program.

Of course if you really care about truly random numbers then you should be using a cryptographic number generator or to give them their full name a cryptographically secure pseudo-random number generator.  Obviously the pseudo comes from the fact that truly random number sequences are inherently impossible from something that is predictable (your computer).  The idea is to get a high entropy (randomness) from a high quality source such as a hardware random number generator or perhaps an unpredictable system process.  It's possible in the .NET framework to get a more random random number using the RNGCryptoServiceProvider as a backing to a class that derives from System.Random which fortunately is not sealed and it's public methods are virtual.  I'll leave that for you to fill out the details though.  Obviously the trade off here is for speed, the more truly random the number becomes the slower is to create that number.  Which is why at the end of the day as long as you understand it's limitations then Random is probably random enough for what you need to do and why cryptographically secure number generators are used only when you need to ensure a sufficient level of randomness in uses like encryption where the loss of speed is acceptable for the gain in security.  

There is a final option though, if you want a combination of speed and randomness why not just use the randomness of the RNGCryptoServiceProvider to create the seed for a new instance of Random()

    public static Random GetRandom()
    {
        var crytoServicePorvider = new RNGCryptoServiceProvider();
        var randomBytes = new byte[sizeof (int)];
        crytoServicePorvider.GetBytes(randomBytes);
        return new Random(BitConverter.ToInt32(randomBytes, 0));
    }