2

Is it guaranteed that random_device won't start at the same internal state for each new thread? So that the following code is likely to give two distinct values?

#include <iostream>
#include <random>
#include <thread>
#include <mutex>

using namespace std;

int main()
{
    auto thr = []()
    {
        static mutex mtx;
        mtx.lock();
        cout << random_device()() << " " << endl;
        mtx.unlock();
    };
    thread t1( thr );
    thread t2( thr );
    t1.join();
    t2.join();
}
Bonita Montero
  • 2,817
  • 9
  • 22

1 Answers1

-1

There is no such guarantee.

On cppreference we can read

std::random_device may be implemented in terms of an implementation-defined pseudo-random number engine if a non-deterministic source (e.g. a hardware device) is not available to the implementation. In this case each std::random_device object may generate the same number sequence.

It's basically up to the implementation.

Another thing is that there is a performance cost to creating new random_devices. Better to re-use the same one.

auto thr = []()
{
    static mutex mtx;
    static random_device rd{};
    mtx.lock();
    cout << rd() << " " << endl;
    mtx.unlock();
};
super
  • 12,335
  • 2
  • 19
  • 29
  • I know, but I omitted the separate random_device for simplicity and it doesn't hurt in this example. – Bonita Montero Oct 12 '19 at 11:14
  • @BonitaMontero I think the point is that if you re-use the same `random_device` you are guaranteed to get distinct values (unless the implementation only ever return one value). So it does matter quite a lot in the context of this example. – super Oct 12 '19 at 12:01
  • Re-using random_device across thread-boundaries doesn't make sense. It's not thread-safe for sure. – Bonita Montero Oct 12 '19 at 14:45
  • @BonitaMontero Not sure what you are refering to. Depending on the implementation it can be perfectly thread safe. It's also not used across thread boundaries in the example. Generally you only use it to seed a PRNG, so you would pass either the RNG or the seed to a thread in a thread-safe manner. – super Oct 12 '19 at 15:58
  • It's not thread-safe for sure since the usual mutex-locking can have at least the same overhead as yielding a new random number. Mutexes are built on top of atomic operations, usuallay LOCK XADD on x86, which are about 20+ clock-cycles (and you need two, one for locking and one for unlocking). And when you have contentenion, thereby getting a kernel-wait and wakeup, you can forget about performance. So if you want thread-safe random_device, I'm pretty sure you're imposed to do the locking yourself. – Bonita Montero Oct 12 '19 at 16:07
  • 1
    It's not for sure, since it's implementation defined. Since `random_device` only ever is used for initializing your RNG, performance is maybe not the most important thing. AFAIK a linux machine will use `/dev/urandom`, which is thread safe. A windows machine will use some WinAPI call. I don't see it as very unlikely that would be thread safe as well. But it's **not guaranteed** by the c++ standard. – super Oct 12 '19 at 16:13
  • Windows doesn't use a random-number-generator of the kernel, but Linux does. How stupid is that? No one expects crypto-proof random-number-generation from a runtime-lib-random-generator but fast algorithms. – Bonita Montero Oct 12 '19 at 16:52
  • It is related to what you said. You told that both rely on kernel-random-facilities. But that's only true for Linux. And under Linux it is not even initializing the random-number-generator from the kernel, but is constantly updtating its state from the kernel. – Bonita Montero Oct 12 '19 at 17:04