【问题标题】:C++ STL Multithreading, running computation in parallelC++ STL 多线程,并行运行计算
【发布时间】: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


【解决方案1】:

这是重要的编译错误:

/usr/include/c++/4.9/functional: In instantiation of ‘struct std::_Bind_simple&lt;int (*(std::vector&lt;int&gt;, double, int))(std::vector&lt;int&gt;&amp;, double, int, int)&gt;’:

编译器检测到 countLatticePoints 接受对向量的引用,但传递的是实际向量。您可以通过使用 std::ref 传递对向量的引用来编译它,如下所示:

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

但这是个坏主意,因为现在所有线程都在共享一个向量,而且由于向量不是线程安全的,你只会陷入一场灾难。

你可以改变 countLatticePoints 来接受一个实际的向量,然后你就不再需要 std::ref 了。然后该函数获取它自己的向量,该向量是线程安全的,但随后每个线程都会执行整个向量这不是您想要的

所有这一切的答案是向每个线程传递其自己的实际向量(不是引用)以确保线程安全,但从迭代器对构造每个向量,使其仅包含一小部分项,以便每个线程获得不同的一组数据。

还有其他问题,例如线程是如何连接的,但它们需要一个新问题,因为它们与您提出的问题无关。

【讨论】:

    猜你喜欢
    • 2018-04-12
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-28
    相关资源
    最近更新 更多