【发布时间】:2016-05-23 00:16:49
【问题描述】:
#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...>)
^
【问题讨论】:
-
除了编译错误之外,您还有一个更大的问题。似乎每个线程都会尝试将
push_back() 转换为相同的std::vector。由于std::vector不保证线程安全,这将导致未定义的行为。 -
是的,这整件事已经无法挽救了。
-
并行计算并不像为相同的代码启动一堆线程那么简单。多线程引入了许多必须正确处理的并发和锁定问题。就像我说的:
std::vector不是线程安全的。如果没有正确的互斥锁,您不能有来自同一向量的多个线程push_back()和pop_back()。句号。故事结束。 -
当然可以,但这里有一个更好的主意:花一些时间研究并发和多线程。找一本关于这个主题的好书。如果您不完全了解正在发生的事情以及所涉及的所有问题,那么您将一直在努力追查并难以重现错误。
-
迭代地排列你的点(没有递归),将工作负载划分到多个线程变得更容易。
标签: c++ multithreading c++11 stl