0

I have a rather large C++ library and need to deal with random number generations in different portions of the code (i.e. different methods or classes).

While the question How do I generate thread-safe uniform random numbers? is concerned to the case when the lifespan of the random engine is limited to a (parallel) function call, here instead, I'm looking for a way of having one (one per thread) generator that survives for the whole program.

The main structure of the code is based on an Algorithm class that at every iteration calls an update() method from several instances of class B (the number of instances may change at every iteration). In the update() method, several random numbers are generated.

To avoid dealing with random number engines, I encapsulated a 'global' RNG in a static class:

class Rng {
 public:
  static Rng &Instance() {
    static Rng s;
    return s;
  }

  std::mt19937_64 &get() { return mt; }
  void seed(int seed_val) { mt.seed(seed_val); }

 private:
  Rng(int seed_val = 20201103) { mt.seed(seed_val); }
  ~Rng() {}

  Rng(Rng const &) = delete;
  Rng &operator=(Rng const &) = delete;

  std::mt19937_64 mt;
};

Now I realize that the update of the instances of class B can be performed in parallel and independently, and would like to use openmp to do something like

std::vector<B> b_instances = .... ;
#pragma omp parallel for
for (auto& b: b_instances) b.update()
....
auto& rng = Rng::Instance().get();
... do more stuff with rng ...

A minimal example of the update method could be

B::update() {
    auto& rng = Rng::Instance().get();
    std::normal_distribution<double> distribution(5.0,2.0);
    this->x = distribution(rng);
}

My question now is: how can I call the update methods in parallel without incurring in any race from the static rng? I read that the best solution would be to have a dedicated RNG for every thread, but I still would like to keep the static Rng class. What could be an elegant solution?

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
mariob6
  • 469
  • 1
  • 6
  • 16
  • 2
    "here instead, I'm looking for a way of having one (one per thread) generator" That seems to imply one per thread (`thread_local`). "I still would like to keep the static Rng class." This would be `static`, one for the whole program. Which one is it? And if the latter, no, you'll not find "elegant" solutions unless mutexes or similar primitives are "elegant" in your eyes. – Mat Nov 20 '20 at 22:38
  • That's exactly what I'm asking. Since I'm not proficient in parallel programming, what is the best solution? Is it possible to have a std::vector of random engines (one per thread) and calling Rng::Instance().get(std::this_thread::get_id()) for instance? Again I'm very new to this – mariob6 Nov 20 '20 at 22:52
  • 1
    The singleton defeats the purpose, it means you have only one. Making it thread_local might solve the problem, but you use OMP, where you must check how you make then thread_local, but that will then only be for that loop. – Surt Nov 20 '20 at 23:37
  • @Surt, I'm sorry but I didn't completely get your point. Could you be more specific? – mariob6 Nov 21 '20 at 06:34
  • Having a shared vector/array of random engines should in principle work. You should just keep in mind that the Mersenne Twister in particular has a **very** big state, so having several of them takes some space. You might also want to make sure that you don't have any false sharing (several generators with state on the same cache line). For that one could wrap the generator in a helper class containing some padding. – paleonix Nov 21 '20 at 13:10
  • Thanks, this is very helpful. But what do you mean by cache line and padding? – mariob6 Nov 21 '20 at 16:30
  • 1
    Read the standrd on "omp threadprivate" https://www.openmp.org/spec-html/5.0/openmpsu104.html It gets you just what you are asking for. One instance of a static variable per thread. Of course, parallel random number generation requires more than that (since you need to ensure that the per-thread sequences do not overlap); so also read Parallel Random Numbers: As Easy as 1, 2, 3 - The Salmons http://www.thesalmons.org/john/random123/papers/random123sc11.pdf – Jim Cownie Nov 23 '20 at 11:08

0 Answers0