vendredi 28 février 2020

Safe random number generation using rand() or std::random_device in C++

I'm having some hard time finding convincing sources on the thread safety of random number generation in C++.

The application I am working on currently has few threads accessing the random number generation, but it might have more in the future.

The first thing I used was:

int randomInRange(const int min, const int max)
{
    srand(time(0));
    return min + (rand() % max);
}

From what I found out this is wrong in the sense that because the seed is set for every call, it impacts the statistical randomness of the rand() function and performance negatively.

Next thing I tried was using a singleton which holds a single instance of std::mt19937:

// RandomHelper.h
class RandomHelper
{
private:
    std::mt19937 engine;

    // Singleton
    RandomHelper() : engine(std::random_device()()) {}

public:
    static RandomHelper& getInstance();

    int randomInRange(int min, int max)
    {
        std::uniform_int_distribution<int> uidist(min, max);
        return uidist(engine);
    }
};

// RandomHelper.cpp
RandomHelper& RandomHelper::getInstance()
{
    static RandomHelper instance;
    return instance;
}

Which should help with the statistical randomness. But for this I understand that it would be better to have a std::mt19937 instance per-thread.

I am not sure I understand why.

Is this because if multiple threads would call RandomHelper::getInstance().randomInRange(.., ..) at the exact same time they would get the same result? AKA it's not thread-safe?

To avoid the possibility of this I have now implemented the following:

int randomInRange(const int min, const int max)
{
    thread_local std::mt19937 engine(std::random_device{}());
    std::uniform_int_distribution<int> uidist(min, max);
    return uidist(engine);
}

This looks to be the best solution so far, but I can't find much information on the thread safety of std::mt19937 or std::random_device to see whether it's actually needed to have a thread_local variant of those versus the single instance in the singleton.

I am willing to do more research but I have no idea on where to look other than the usual C++ references which don't mention anything about thread-safety as far as I can see.




Aucun commentaire:

Enregistrer un commentaire