使用std :: async和需要函数和参数参数的函数

时间:2016-02-12 16:38:42

标签: c++ multithreading c++14

我正在研究多线程C ++ vapply函数,它将函数应用于向量的每个元素。诀窍是我不想为向量中的每个元素创建一个线程;我宁愿创建一定数量的线程,并为每个线程分配一个矢量来处理。

但是,我不确定如何使用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 个答案:

答案 0 :(得分:1)

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