2016-05-23 29 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。该函数然后获取它自己的向量,这是线程安全的,但是然后每个线程执行整个向量,这不是您想要的

所有这些的答案是将每个线程自己的实际向量(不是引用)传递给线程安全,但是从一个迭代器对构造每个向量,以便它只包含一小部分项目,以便每个线程都获得一个不同的数据集。

还有其他问题,如线程如何加入,但他们需要一个新的问题,因为他们与你问的问题无关。