-1

The task is to calculate PI with MonteCarlo and OpenMP. The code is below:

#include <omp.h>
#include <chrono>
#include <iostream>
#include <random>

#define numSamples 10000000

int main() {

    double I, t1, t2, x, y;
    std::default_random_engine engine;
    auto seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::uniform_real_distribution<double> distr(-1.0, 1.0);
    engine.seed(seed);


    size_t counter = 0;

    t1 = omp_get_wtime();

#pragma omp parallel for reduction(+ : counter) private(x, y) firstprivate(engine, distr)
    for (size_t i = 0; i < numSamples; ++i) {

        x = distr(engine);
        y = distr(engine);

        if (x * x + y * y <= 1) {
            counter++;
        }
    }

    t2 = omp_get_wtime();

    I = 4.0 * (double)counter / numSamples;
    std::cout << "I = " << I << ", t = " << t2 - t1 << "." << std::endl;

    return 0;
}

There is a question. I should have the engine variable private for every thread and it's understandable. But as I've noticed there is no need for making distr variable private. There is no race conditions in this case (the execution time of the program is the same if this variable private or not). Why it happens this way?

Rumato
  • 147
  • 7
  • Why does what happen? – Shawn Nov 28 '19 at 19:52
  • In the code the variable "distr" is firstprivate but I can make it shared and the code will work the same way. So I will have shared variable with no race condition. How is it possible? – Rumato Nov 28 '19 at 19:55
  • Why are you going out of your way to use a clock-based seed? Don't. Use [`random_device`](https://en.cppreference.com/w/cpp/numeric/random/random_device) to make it truly random. – tadman Nov 28 '19 at 19:57
  • Is there anything in the distribution function that requires mutable state to cause a race? I doubt it. – Shawn Nov 28 '19 at 19:58

1 Answers1

1

std::uniform_real_distribution<double> is a simple helper class. It stores two variables that indicate the range of the distribution and that's it. Its operator () is a const method. So using it in several threads shouldn't cause any data races.

That's being said, I don't remember it being promised by the standart - not that I read it much - and copying it takes little to no time and space. So why not copy just in case? not that anybody should really care about it. Probably writer didn't bother. Though, there could be various implementations of C++11 with odd stuff.

However, in CUDA C++ and GPU environment being privately owned by a thread typically results in a better performance over shared ownership (but not always). Though I don't know whether "omp.h" can utilize something like that or not.

ALX23z
  • 4,456
  • 1
  • 11
  • 18