Is the random number generator in Haskell thread-safe? Is the random number generator in Haskell thread-safe? multithreading multithreading

Is the random number generator in Haskell thread-safe?


There is a function named newStdGen, which gives one a new std. gen every time it's called. Its implementation uses atomicModifyIORef and thus is thread-safe.

newStdGen is better than get/setStdGen not only in terms of thread-safety, but it also guards you from potential single-threaded bugs like this: let rnd = (fst . randomR (1,5)) <$> getStdGen in (==) <$> rnd <*> rnd.

In addition, if you think about the semantics of newStdGen vs getStdGen/setStdGen, the first ones can be very simple: you just get a new std. gen in a random state, chosen non-deterministically. On the other hand, with the get/set pair you can't abstract away the global program state, which is bad for multiple reasons.


I would suggest you to use getStdGen only once (in the main thread) and then use the split function to generate new generators. I would do it like this:

Make an MVar that contains the generator. Whenever a thread needs a new generator, it takes the current value out of the MVar, calls split and puts the new generator back. Due to the functionality of an MVar, this should be threadsafe.


By itself, getStdGen and setStdGen are not thread safe in a certain sense. Suppose the two threads both perform this action:

do ...   g <- getStdGen   (v, g') <- someRandOperation g   setStdGen g'

It is possible for the threads to both run the g <- getStdGen line before the other thread reaches setStdGen, therefore they both could get the exact same generator. (Am I wrong?)

If they both grab the same version of the generator, and use it in the same function, they will get the same "random" result. So you do need to be a little more careful when dealing with random number generation and multithreading. There are many solutions; one that comes to mind is to have a single dedicated random number generator thread that produces a stream of random numbers which other threads could consume in a thread-safe way. Putting the generator in an MVar, as FUZxxl suggests, is probably the simplest and most straightforward solution.

Of course I would encourage you to inspect your code and make sure it is necessary to generate random numbers in more than one thread.