I have seen several usages of std::mt19937
like following:
#include <random>
size_t get_rand()
{
static thread_local std::mt19937 generator(time(0));
std::uniform_int_distribution<int> distribution(0, 10);
return distribution(generator);
}
I want to find out what benefits comes from using static thread_local
rather than static
here. // first static
is redundant
I understand that in the second case generator
has lifetime until thread is finished.
Are there other benefits/differences in common or this particular case?
If it wasn't thread_local
, then calling get_rand
from multiple threads would cause a data race and therefore undefined behavior.
Although the static
initialization is always safe, even with multiple threads calling it, the call to the generator in distribution(generator)
, which modifies the generator's internal state, is not.
With thread_local
each thread has its own generator and so there is no issue with them calling the function unsynchronized.
Also note that time(0)
is a bad idea. General issue with that as a seed aside, if multiple threads call the function at a similar time, they are likely to be seeded with the same value and then the random numbers in the threads will all be identical (which is very likely not what you want).
A somewhat better seeding would be
thread_local std::mt19937 generator(std::random_device{}());
instead, assuming your platform implements std::random_device
as a proper source of randomness (which should generally be the case, but e.g. is not on some versions of MinGW). (Be careful though if your platform does not properly implement std::random_device
. In that case it might always produce the same sequence of numbers.) For more details on seeding the standard library random number generators see e.g. this question. Also note that even with platform support, this is still a mediocre seeding since it (typically) uses only 32bits of entropy. See e.g. this blog post for some details about these issues. Correct seeding is a quite non-trivial problem.
For a declaration at block scope static
is redundant by the way when using thread_local
.