当前位置: 动力学知识库 > 问答 > 编程问答 >

C++ STL Multithreading, running computation in parallel

问题描述:

#include <iostream>

#include <cmath>

#include <numeric>

#include <vector>

#include <algorithm>

#include <thread>

#include <stdio.h>

// Determines if a point of dimension point.size() is within the sphere

bool isPointWithinSphere(std::vector<int> point, const double &radius) {

// Since we know that the sphere is centered at the origin, we can simply

// find the euclidean distance (square root of the sum of squares) and check to

// see if it is less than or equal to the length of the radius

//square each element inside the point vector

std::transform(point.begin(), point.end(), point.begin(), [](auto &x){return std::pow(x,2);});

//find the square root of the sum of squares and check if it is less than or equal to the radius

return std::sqrt(std::accumulate(point.begin(), point.end(), 0, std::plus<int>())) <= radius;

}

// Counts the number of lattice points inside the sphere( all points (x1 .... xn) such that xi is an integer )

// The algorithm: If the radius is a floating point value, first find the floor of the radius and cast it to

// an integer. For example, if the radius is 2.43 then the only integer points we must check are those between

// -2 and 2. We generate these points by simulating n - nested loops using recursion and passing each point

// in to the boolean function isPointWithinSphere(...), if the function returns true, we add one to the count

// (we have found a lattice point on the sphere).

int countLatticePoints(std::vector<int> &point, const double radius, const int dimension, int count = 0) {

const int R = static_cast<int>(std::floor(radius));

for(int i = -R; i <= R; i++) {

point.push_back(i);

if(point.size() == dimension){

if(isPointWithinSphere(point, radius)) count++;

}else count = countLatticePoints(point, radius, dimension, count);

point.pop_back();

}

return count;

}

int main(int argc, char ** argv) {

std::vector<int> vec {};

std::vector<std::thread> threads;

auto max_threads = std::thread::hardware_concurrency();

for(unsigned i = 0; i < max_threads; ++i)

threads.push_back(std::thread(countLatticePoints, vec, atof(argv[1]), atoi(argv[2])));

std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));

return 0;

}

I am trying to run the above computation in parallel. Basically, I want to call the function countLatticePoints(vec, 1.05, 3) so that the maximum number of threads on my system are running the computation and returning one final result. I am having difficulty in setting this up. What I have tried is to have all the threads join my computation but I am receiving the following very undecipherable error message.

 g++ nDimensionalSphere.cpp -o nDimensionalSphere -std=c++14 -pthread

In file included from /usr/include/c++/4.9/thread:39:0,

from nDimensionalSphere.cpp:6:

/usr/include/c++/4.9/functional: In instantiation of ‘struct std::_Bind_simple<int (*(std::vector<int>, double, int))(std::vector<int>&, double, int, int)>’:

/usr/include/c++/4.9/thread:140:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = int (&)(std::vector<int>&, double, int, int); _Args = {std::vector<int, std::allocator<int> >&, double, int}]’

nDimensionalSphere.cpp:56:92: required from here

/usr/include/c++/4.9/functional:1665:61: error: no type named ‘type’ in ‘class std::result_of<int (*(std::vector<int>, double, int))(std::vector<int>&, double, int, int)>’

typedef typename result_of<_Callable(_Args...)>::type result_type;

^

/usr/include/c++/4.9/functional:1695:9: error: no type named ‘type’ in ‘class std::result_of<int (*(std::vector<int>, double, int))(std::vector<int>&, double, int, int)>’

_M_invoke(_Index_tuple<_Indices...>)

^

网友答案:

This is the important compilation error:

/usr/include/c++/4.9/functional: In instantiation of ‘struct std::_Bind_simple<int (*(std::vector<int>, double, int))(std::vector<int>&, double, int, int)>’:

The compiler is detecting that countLatticePoints accepts a reference to a vector but an actual vector is being passed. You can make it compile by passing a reference to a vector with std::ref like this:

threads.push_back(std::thread(&countLatticePoints, std::ref(vec), atof(argv[1]), atoi(argv[2]), 0 /*the default parameter*/));

But that is a BAD idea because now all the threads are sharing the one vector and since vectors aren't threadsafe you are just walking into a disaster.

You could change countLatticePoints to accept an actual vector and then you wouldn't need the std::ref any more. The function then gets it's own vector which is threadsafe but then every thread does the entire vector which is not what you want.

The answer to all this is to pass each thread its own actual vector (not a reference) to be threadsafe but construct each vector from an iterator pair so that it contains only a fraction of the items so that every thread gets a different set of data.

There are other problems like how the threads are being joined but they need a new question because they are unrelated to the question you asked.

分享给朋友:
您可能感兴趣的文章:
随机阅读: