3

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?

0

1 Answer 1

9

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.

Sign up to request clarification or add additional context in comments.

4 Comments

1) Theoretically I could synchronize threads, for instance using spinlock, and it would work fine (but slower)?
"thread_local can appear together with static or extern to adjust linkage" source. So static is redundant only in some cases, like this one where the variable is restricted to the scope of a function. When a variable is declared at namespace scope, static can make a difference
@mouse_00 Yes, if you make sure that the function is not called unsynchronized, using atomics, mutices or fences, then there is no issue with not using thread_local. But usually a random number generator is supposed to produce the numbers quickly and there is no real benefit, except saving a few bytes of storage, with not using thread_local here.
@NikosAthanasiou Yes, correct. I have clarified the answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.