C ++ STL多线程,并行运行计算 [英] C++ STL Multithreading, running computation in parallel

查看:1370
本文介绍了C ++ STL多线程,并行运行计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  #include< iostream> 
#include< cmath>
#include< numeric>
#include< vector>
#include< algorithm>
#include< thread>
#include< stdio.h>


//确定一个点point.size()是否在球体内
bool isPointWithinSphere(std :: vector< int> point,const double& radius ){

//因为我们知道球体以原点为中心,我们可以简单地
//找到欧几里得距离(平方和的平方根)并检查
//看它是否小于或等于半径的长度

//在点矢量内的每个元素
std :: transform(point.begin() ,point.end(),point.begin(),[](auto& x){return std :: pow(x,2);});

//找到平方和的平方根,并检查它是否小于或等于半径
return std :: sqrt(std :: accumulate(point.begin( ),point.end(),0,std :: plus< int>()))
}

//计算球体内的格点数(所有点(x1 ... xn)使得xi是整数)

//算法:如果半径是浮点值,首先找到半径的底部并将其转换为
//一个整数。例如,如果半径是2.43,那么我们必须检查的唯一整数点是
// -2和2之间的那些。我们通过使用递归模拟n嵌套循环并传递每个点来生成这些点
// in to the boolean function isPointWithinSphere(...),如果函数返回true,我们向count
//添加一个(我们在球体上找到了一个点阵点)。

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>线程;
auto max_threads = std :: thread :: hardware_concurrency();

for(unsigned i = 0; 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 
在从/usr/include/c++/4.9/thread:39:0包含的文件中,
来自nDimensionalSphere.cpp:6:
/usr/include/c++/4.9/functional:在实例化'struct std :: _Bind_simple< int(*(std :: vector< int> double,int))(std :: vector< int& ,double,int,int)>':
/usr/include/c++/4.9/thread:140:47:需要从'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:从这里需要
/usr/include/c++/4.9/functional:1665:61:error: '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:没有在'std :: result_of< int(*(std :: vector< int> ;,double,int))(std :: vector& amp; double,int,int)>'
_M_invoke(_Index_tuple< _Indices ...>)
^


解决方案

这是重要的编译错误:



/ usr / include / c ++ / 4.9 / functional:在实例化'struct std :: _ Bind_simple< int(*(std :: vector< int& ))(std :: vector< int&& double,int,int)>':



countLatticePoints接受对向量的引用,但实际向量正在传递。你可以通过向std :: ref的引用传递一个引用来编译:



threads.push_back(std :: thread & countLatticePoints,std :: ref(vec),atof(argv [1]),atoi(argv [2]),0 / *默认参数* /));



但这是一个BAD想法,因为现在所有的线程都共享一个向量,因为向量不是线程安全的,你只是走进一场灾难。 / p>

你可以改变countLatticePoints来接受一个实际的向量,然后你不再需要std :: ref了。然后函数得到它自己的向量,这是线程安全的,但然后每个线程做整个向量这不是你想要的



所有这些都是通过每个线程自己的实际向量(不是引用)是线程安全的,但构造每个向量从一个迭代器对,以便它只包含项目的一小部分,使每个线程获得一组不同的数据。 p>

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


#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;
}

I am trying to run the above computation in parallel. Basically, I want to call the function countLatticePoints(vec, 1.05, 3) so that the maximum number of threads on my system are running the computation and returning one final result. I am having difficulty in setting this up. What I have tried is to have all the threads join my computation but I am receiving the following very undecipherable error message.

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

解决方案

This is the important compilation error:

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

The compiler is detecting that countLatticePoints accepts a reference to a vector but an actual vector is being passed. You can make it compile by passing a reference to a vector with std::ref like this:

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

But that is a BAD idea because now all the threads are sharing the one vector and since vectors aren't threadsafe you are just walking into a disaster.

You could change countLatticePoints to accept an actual vector and then you wouldn't need the std::ref any more. The function then gets it's own vector which is threadsafe but then every thread does the entire vector which is not what you want.

The answer to all this is to pass each thread its own actual vector (not a reference) to be threadsafe but construct each vector from an iterator pair so that it contains only a fraction of the items so that every thread gets a different set of data.

There are other problems like how the threads are being joined but they need a new question because they are unrelated to the question you asked.

这篇关于C ++ STL多线程,并行运行计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆