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

我想並行地運行上述計算。基本上,我想調用函數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

除了編譯錯誤,你還有一個更大的問題。看起來每個線程都會嘗試'push_back'()到同一個'std :: vector'。由於'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接受的載體中的參考,但實際的矢量被傳遞。你可以把它傳遞一個參照矢量性病編譯:: REF這樣的:

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

但是,這是一個壞主意因爲現在所有的線程共享的一個載體,因爲向量不是線程安全的,你只是步入一場災難。

你可以改變countLatticePoints接受一個實際的向量,然後你將不再需要std :: ref。該函數然後獲取它自己的向量,這是線程安全的,但是然後每個線程執行整個向量,這不是您想要的

所有這些的答案是將每個線程自己的實際向量(不是引用)傳遞給線程安全,但是從一個迭代器對構造每個向量,以便它只包含一小部分項目,以便每個線程都獲得一個不同的數據集。

還有其他問題,如線程如何加入,但他們需要一個新的問題,因爲他們與你問的問題無關。