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 callingget_randfrom multiple threads would cause a data race and therefore undefined behavior.Although the
staticinitialization is always safe, even with multiple threads calling it, the call to the generator indistribution(generator), which modifies the generator's internal state, is not.With
thread_localeach 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
instead, assuming your platform implements
std::random_deviceas 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 implementstd::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
staticis redundant by the way when usingthread_local.