Многопоточность C++ STL, параллельное выполнение вычислений

#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;
}

Я пытаюсь выполнить вышеуказанные вычисления параллельно. В принципе, я хочу вызвать функцию countLatticePoints(vec, 1.05, 3)так, чтобы максимальное количество потоков в моей системе запускали вычисление и возвращали один конечный результат. Я испытываю трудности в настройке этого. То, что я пытался, чтобы все потоки присоединиться к моим вычислениям, но я получаю следующее Очень неразборчивое сообщение об ошибке.

 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...>)
         ^ 

1 ответ

  1. Это важная ошибка компиляции:

    /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)>’:

    Компилятор обнаруживает, что countLatticePoints принимает ссылку на вектор, но фактический вектор передается. Вы можете сделать его компилировать, передавая ссылку на вектор с помощью std:: ref, как это:

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

    Но это плохая идея, потому что теперь все потоки разделяют один вектор, и поскольку векторы не являются threadsafe, вы просто идете в катастрофу.

    Вы можете изменить countLatticePoints, чтобы принять фактический вектор, и тогда вам больше не понадобится std::ref. Затем функция получает собственный вектор, который является threadsafe, но затем каждый поток делает весь вектор, который не является тем, что вы хотите .

    Ответ на все это-передать каждому потоку свой собственный фактический вектор (не ссылка), чтобы быть threadsafe, но построить каждый вектор из пары итераторов так, чтобы он содержал только часть элементов, чтобы каждый поток получал другой набор данных.

    Есть и другие проблемы, например, как объединяются потоки, но им нужен новый вопрос, потому что они не связаны с вопросом, который вы задали.