2016-05-23 11 views
0
#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; 
} 

Ich versuche, die obige Berechnung parallel auszuführen. Grundsätzlich möchte ich die Funktion countLatticePoints(vec, 1.05, 3) aufrufen, so dass die maximale Anzahl von Threads auf meinem System die Berechnung ausführt und ein Endergebnis zurückgibt. Ich habe Schwierigkeiten, dies aufzustellen. Was ich versucht habe, ist, dass alle Threads zu meiner Berechnung gehören, aber ich bekomme die folgende, sehr nicht entzifferbare Fehlermeldung.C++ STL Multithreading, laufende Berechnung parallel

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

Zusätzlich zu dem Kompilierungsfehler haben Sie ein viel größeres Problem. Es scheint, dass jeder Thread versucht, "push_back"() zu demselben "std :: vector" zu senden. Da 'std :: vector' keine Threadsicherheit garantiert, führt dies zu undefiniertem Verhalten. –

+0

@SamVarshavchik Oh aber das 'pop_back' am Ende der Schleife macht noch mehr Spaß :) – kfsone

+2

Ja, das ganze Ding ist gerade jenseits des Punktes der Rettung. –

Antwort

0

Dies ist wichtig, Kompilierung Fehler:

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

Der Compiler erkennt, dass countLatticePoints auf einen Vektor, der eine Referenz nimmt, aber ein tatsächliches Vektor übergeben wird. Sie können es, indem Sie einen Verweis auf einen Vektor mit std machen kompilieren :: wie folgt Ref:

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

Aber das ist eine schlechte Idee weil jetzt alle Fäden teilen sich den einen Vektor und da Vektoren sind nicht threadsicher, du gehst gerade in eine Katastrophe.

Sie könnten countLatticePoints ändern, um einen tatsächlichen Vektor zu akzeptieren, und dann würden Sie das std :: ref nicht mehr benötigen. Die Funktion erhält dann ihren eigenen Vektor, der threadsicher ist, aber dann führt jeder Thread den gesamten Vektor , was nicht das ist, was Sie wollen. Die Antwort auf all dies ist, jedem Thread seinen eigenen tatsächlichen Vektor (keine Referenz) zu geben, der threadsicher ist, aber jeden Vektor aus einem Iteratorpaar zu konstruieren, so dass er nur einen Bruchteil der Elemente enthält, so dass jeder Thread ein erhält andere Datenmenge.

Es gibt andere Probleme wie, wie die Threads verbunden werden, aber sie brauchen eine neue Frage, weil sie nicht verwandt sind mit der Frage, die Sie gestellt haben.