Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::random_device and multithreading

329 views
Skip to first unread message

Andrey Tarasevich

unread,
May 9, 2022, 11:28:50 AM5/9/22
to
Hello

There are quite a few questions on the Net about using `<random>` in
multithreaded environment, but virtually everything I find talks about
sharing `std::random_device`, `std::mt19937`, etc. objects between threads.

My question is different. Let's say we are *not* sharing these objects
at all. Let's say we are running multiple thread functions, each of
which declares its own `std::random_device` locally and using the
device's `()` operator

void thread_function()
{
std::random_device rd;
...
auto r = rd(); // ???
...
}

Looks fine at the first sight. However, `std::random_device`s
specification implies that it can be based on a shared global resource,
like a hardware source of randomness or some other shared entropy pool,
whose hardware/software nature is opaque to us.

So, if it does use a shared resource, does the standard give us a
guarantee that polling automatic (as in the example above) or
`thread_local` objects of `std::random_device` type is thread-safe?

I mean, to me it is virtually obvious that such guarantee should exist.
Otherwise, I'd be weird, to put it mildly. But perhaps someone can quite
the relevant portion of the spec...

--
Best regards,
Andrey

Juha Nieminen

unread,
May 10, 2022, 1:16:19 AM5/10/22
to
Andrey Tarasevich <andreyta...@hotmail.com> wrote:
> So, if it does use a shared resource, does the standard give us a
> guarantee that polling automatic (as in the example above) or
> `thread_local` objects of `std::random_device` type is thread-safe?

I somehow have the impression that the principle is that when the programmer
is not given a choice about whether something is shared or not, it will be
guaranteed to be thread-safe or thread-local (if it is indeed shared).

For example you have no choice about the internal implementation details
of std::fopen(), therefore it has to be thread-safe. errno is guaranteed
to be thread-local (again, because you have no choice over where it's
located). Rather obviously 'new' (and 'malloc()') has to be thread-safe
because you don't have a "local new" choice. (And this is one of the reasons
why dynamic memory allocation is so slow, even in single-threaded programs.)
A function-local static is guaranteed to be thread-safe.

Thus it would make sense that if the programmer has no choice over whether
std::random_device uses some shared resource nor not, it has to be thread-safe
if it doesn't.

(Of course there's at least one argument against the above: The programmer
has no choice about the internal details of std::cout, yet it's not
guaranteed to be thread-safe. Or, more precisely, the order in which
different characters are outputted is not guaranteed if more than one
thread uses it at the same time. I assume it's at least guaranteed that
std::cout will not outright malfunction and crash the program even if
it's used simultaneously by multiple threads...)

Juha Nieminen

unread,
May 10, 2022, 1:19:47 AM5/10/22
to
Juha Nieminen <nos...@thanks.invalid> wrote:
> A function-local static is guaranteed to be thread-safe.

I meant to say that the *initialization* of a function-local static is
guaranteed to be thread-safe. (*Using* it is rather obviously not. Nor
how the initialization value is calculated, because that's up to the
programmer.)
0 new messages