Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread safety of std::random_device

I have some code which looks a bit like this:

std::random_device rd;

#pragma omp parallel
{
    std::mt19937 gen(rd());
    #pragma omp for
    for(int i=0; i < N; i++)
    {
        /* Do stuff with random numbers from gen() */
    }
}

I have a few questions:

  • Is std::random_device thread safe? i.e. Is it going to do something unhelpful when several threads call it at once?
  • Is this generally a good idea? Should I be worried about overlapping random number streams?
  • Is there a better way to achieve what I want (independent random number streams in each thread - I'm not too worried about reproducibility at the moment)?

In case it make any difference to the workings of std::random_device I'm primarily running on Windows, though I would like the code to work equally well on Linux and OSX as well.

like image 512
Theolodus Avatar asked Feb 10 '17 10:02

Theolodus


People also ask

Is Random_device thread safe?

There's no docs on the thread safety of this, but it appears to have no state. Hence it should be thread-safe.

How do you ensure thread safety in C++?

An object is thread-safe for reading from multiple threads. For example, given an object A, it is safe to read A from thread 1 and from thread 2 simultaneously. If an object is being written to by one thread, then all reads and writes to that object on the same or other threads must be protected.

Is std :: list size () thread safe?

No, they're not thread-safe.

Is std :: map thread safe?

It isn't thread safe, insert from two threads and you can end up in an inconstant state.


2 Answers

It's not a good idea to use the random device in parallel. Even if it's blocking you may not have troubles with overlapping random number streams but you add a additional synchronization point.

You should set up as many random number engines (RNE) as many threads you want to start, omp_get_num_threads(). Create an std::vector of RNEs and seed them in the sequential part of your program. For seeding you can use the random device and a std::seed_seq.

Then use in each thread the RNE associated with with the thread number, omp_get_thread_num().

Never use the random device to generate random numbers, its's slow and in general not generating uniformly distributed random numbers!

Depending on the quality of the random numbers you need you can use one of the predefined random number generators. If you are doing Monte Carlo simulations or Cryptography be extra careful what algorithm you choose.

You'll find a lot useful information on random engines at https://en.cppreference.com/w/cpp/numeric/random.

like image 142
Brolf Avatar answered Nov 02 '22 00:11

Brolf


On Windows without WinRT, it uses CryptGenRandom, which is thread-safe by https://stackoverflow.com/a/46171432/2024042

On Windows with WinRT, it uses CryptographicBuffer::GenerateRandom. There's no docs on the thread safety of this, but it appears to have no state. Hence it should be thread-safe.

On Linux, it seems to read from /dev/urandom, which is thread-safe.

I read this implementation from libs/random/src/random_device.cpp.

I have no idea what _CXXRT_STD_NAME is in that file, and googling this produces boost::random_device as the only result. Maybe it's nothing!

like image 26
Kevin Yin Avatar answered Nov 02 '22 00:11

Kevin Yin