I wanted to ask for some help in solving the data races in my program. I started with a simulation of how things should work if I were using multithreading and then modified the code so that I can check if I really obtain those results but I don't know how to resolve the data races in the code. Can someone help me please? My code is the following:
void pi(size_t& id, size_t nThread, size_t N, double& pigreco)
{
size_t begin = id* N / nThread;
size_t end = (id+ 1) * N / nThread;
random_device rd; // Object to create random seed
mt19937 generator(rd()); // Mersenne Twister seeded with rd()
uniform_real_distribution<double> distribution(-1.0, 1.0);
for (size_t i = begin; i < end; i++) {
double x = distribution(generator);
double y = distribution(generator);
if (sqrt(x*x + y*y) < 1.0)
pigreco += 4.0 / double(N);
}
}
int main(int argc, char* argv[])
{
if (argc != 2) {
cerr << "Usage: ./pi <number of threads>" << endl;
exit(EXIT_FAILURE);
}
size_t nThread = (size_t)atoi(argv[1]);
size_t N = 100000000;
cout << "Generating " << N << " random values using " << nThread << " thread(s)." << endl;
atomic<double> pigreco = 0.0;
// create threads
vector<thread> threads(nThread);
for (size_t i = 0; i < nThread; i++)
threads[i] = thread(pi, ref(i), nThread, N, ref(pigreco));
for_each(threads.begin(), threads.end(), mem_fn(&thread::join));
cout << "Estimated value for pi: " << pigreco << endl;
exit(EXIT_SUCCESS);
}
I tried using valgrind in order to find the possible data races and I found out that there is one at the first for loop of the main, I think probably because I use 'i' as argument of my function but that I don't know how to resolve it.
I don't know how to resolve the data races in the code.
Then stop using std::thread
, and especially stop passing references to functions on those threads.
Here is one way you could avoid passing any references between threads:
#include <cstdlib>
#include <iostream>
#include <random>
#include <future>
#include <algorithm>
int pimontecarlo(size_t iterations)
{
int count = 0;
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_real_distribution<double> distribution(-1.0, 1.0);
for (size_t i = 0; i < iterations; i++) {
double x = distribution(generator);
double y = distribution(generator);
if (sqrt(x*x + y*y) < 1.0) ++count;
}
return count;
}
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cerr << "Usage: ./pimontecarlo <number of threads>" << std::endl;
exit(EXIT_FAILURE);
}
size_t numThreads { atoi(argv[1]) };
size_t N = 100000000;
std::cout << "Generating " << N << " random values using " << numThreads << " thread(s)." << std::endl;
// create futures
std::vector<std::future<int>> results(numThreads);
for (auto & result : results)
result = std::async(pimontecarlo, N / numThreads);
int count = 0;
for (auto & result : results)
count += result.get();
double pi = (4.0 * count) / N;
std::cout.precision(12);
std::cout << "Estimated value for pi: " << pi << std::endl;
exit(EXIT_SUCCESS);
}