2016-05-23 13 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; 
} 

私は上記の計算を並列に実行しようとしています。基本的には、システム上のスレッドの最大数が計算を実行して最終結果を1つ返すように、関数countLatticePoints(vec, 1.05, 3)を呼び出したいと思います。私はこれを設定するのが難しいです。私が試したことは、すべてのスレッドを計算に参加させることですが、以下の非常に判読不能なエラーメッセージが表示されます。C++ STLマルチスレッド、並列計算での実行

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

コンパイルエラーの他に、はるかに大きな問題があります。各スレッドは同じ 'std :: vector'に対して' push_back'()を試みます。 'std :: vector'はスレッドの安全性を保証するものではないため、未定義の動作になります。 –

+0

@SamVarshavchikああ、ループの最後の 'pop_back'はさらに楽しいです:) – kfsone

+2

ええ、この全体が救済可能な点をちょうど超えています。 –

答えて

0

これは重要なコンパイル・エラーである:

/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ベクトルへの参照を受け入れるが、実際のベクトルが渡されていることを検出しています。

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

しかし、今、すべてのスレッドが1つのベクトルを共有し、ベクトル以来されているので、それは悪いアイデア
です:あなたは、それは、このような参照:: STDとベクトルへの参照を渡すことでコンパイルすることができますスレッドセーフではありませんあなたはただの災害に歩いている。

実際のベクトルを受け入れるようにcountLatticePointsを変更すると、std :: refは必要なくなります。この関数はスレッドセーフな独自のベクターを取得しますが、すべてのスレッドはベクトルを実行します。これはあなたが望むものではありません

すべての答えは、実際の各自の実際のベクトル(参照ではない)をスレッドセーフにすることですが、反復子のペアから各ベクトルを構築して、異なるデータセット。

スレッドがどのように結合されているかのような他の問題がありますが、あなたが尋ねた質問とは無関係なので、新しい質問が必要です。