2016-02-12 801 views
2

我正在研究一个多线程的C++ vapply函数,它将函数应用于向量的每个元素。诀窍是我不想为向量中的每个元素创建一个线程;我宁愿创建一定数量的线程,并给每个线程分配一部分工作空间。使用std :: async函数和参数参数

但我不确定如何使用std::async捕获操作结果。这是我到目前为止有:

vapply.h

#ifndef VAPPLY_H 
#define VAPPLY_H 

#include <vector> 
#include <thread> 
#include <memory> 
#include <future> 
#include <functional> 

class vapply 
{ 
private: 
    template <class Fn, class T> 
    auto docall(Fn&& fn, std::vector <T> &v, size_t begin, size_t end) 
    { 
     using return_type = typename std::result_of <Fn(T)>::type; 
     std::vector <return_type> result; 
     result.reserve(end - begin); 
     for (size_t i = begin; i < end; i++) 
     { 
      result.emplace_back(fn(v[i])); 
     } 
     return result; 
    } 
public: 
    // Constructor 
    template <class Fn, class T> 
    vapply(Fn&& fn, std::vector <T> &v) 
    { 
     size_t maxNumThreads = std::thread::hardware_concurrency() - 1; 
     size_t funcPerThread = v.size()/maxNumThreads; 
     size_t funcModThread = v.size() % maxNumThreads; 

     size_t funcToPerform = 0; 
     for (size_t i = 0; i < v.size(); i += funcToPerform) 
     { 
      funcToPerform = (i == 0) ? funcPerThread + funcModThread : funcPerThread; 
      // this line works fine, extract the results of docall 
      auto p = docall(std::forward <Fn>(fn), v, i, i + funcToPerform); 
      // now I'd like to do the same thing but in a separate thread, but below doesn't compile 
      // auto q = std::async(std::launch::async, &vapply::docall, std::forward <Fn>(fn), v, i, i + funcToPerform); 
     } 
    } 
}; 

#endif /* VAPPLY_H */ 

main.cpp

#include <iostream> 
#include <numeric> 
#include <string> 

#include "vapply.h" 

std::string test1(uint64_t a) 
{ 
    return std::to_string(a); 
} 

int main(int argc, char **argv) 
{ 
    std::vector <uint64_t> v(17); 
    std::iota(v.begin(), v.end(), 0); 
    vapply(test1, v); 
    return 0; 
} 

回答

1

auto q = std::async(std::launch::async, &vapply::docall, std::forward <Fn>(fn), v, i, i + funcToPerform);这行不编译,因为传递的方法作为参数传递给函数它必须是绑定到一个实例,在这种情况下为this。所以使用std::bind或更好这样的拉姆达:auto fut = std::async(std::launch::async, [&] { return docall(std::forward <Fn>(fn), v, i, i + funcToPerform); });获得future的结果,使用其get()方法这样auto q = fut.get();但请记住future::get()被阻塞调用的循环将不运行多个线程,以便调用async()然后future::get() 。而是将期货保存在一个循环中,并在其他循环中为每个未来调用get()。