在c ++ 11中将其他参数包装到variadic参数包中

时间:2015-12-23 14:14:15

标签: c++ multithreading c++11

基于我之前的问题here,我正在编写一个小类来帮助我将工作分发给一堆线程。在构造线程时,我想将循环计数器作为附加参数传递给参数包,以用作thread_id。这可能吗?

qthread.h

#ifndef QTHREAD_H
#define QTHREAD_H

#include <vector>
#include <thread>
#include <memory>

class qthread
{
    std::vector <std::shared_ptr <std::thread>> threads;
public:
    // Constructor
    template <class Fn, class... Args>
    qthread(Fn&& fn, Args&&... args)
    {
        size_t maxNumThreads = std::thread::hardware_concurrency() - 1;
        for(size_t i = 0; i < maxNumThreads; i++)
        {
            // While constructing the thread I would like to also pass i as a thread_id to the function in the parameter packing
            threads.push_back(std::make_shared <std::thread>(std::forward<Fn>(fn), std::forward<Args>(args)...));
        }
    }
    // Destructor
    ~qthread()
    {
        for(auto thr_p:threads)
        {
            thr_p->join();
        }
    }
};

#endif /* QTHREAD_H */

main.cpp

#include <iostream>

#include "qthread.h"

void test(const size_t thread_id, int x)
{
    for(size_t i=0; i < 1000; i++)
    {
        x += i;
    }
    std::cout << "thread: " << thread_id << ", total: " << x << "\n";
}

int main()
{
    qthread(test, 5); // Distribute the 'test' task to n threads -- note that this doesn't work in this case since the function requires two parameters
}

1 个答案:

答案 0 :(得分:4)

正如评论中T.C.所述,a std::thread constructor有以下签名:

template< class Function, class... Args > 
explicit thread( Function&& f, Args&&... args );

此构造函数将调用copy / move函数f和参数args...到其可线程访问的存储,然后在新线程中调用f(args...)

使用......

就足够了
threads.push_back(
    std::make_shared <std::thread>(
        std::forward<Fn>(fn), thread_id, std::forward<Args>(args)...
    )
) 

...将thread_id绑定为fn的参数。

这将导致类似于:

的函数调用
fn(thread_id, args...);

通常,如果要将某些参数绑定到函数并获取将包装前一个参数的新可调用对象,则需要使用lambda或struct

C ++ 14示例(假设线程id是第一个参数)

threads.push_back(
    std::make_shared <std::thread>(
        [thread_id, &fn](auto&&... args) -> decltype(auto)
        { 
            // "Bind" `_thread_id` as first argument of `fn`.
            return std::forward<Fn>(fn)(thread_id, 
                std::forward<decltype(args)>(args)...); 
        }, 
        std::forward<Args>(args)...
    )
);

C ++ 11示例(假设线程id是第一个参数)

template<typename TF>
struct bind_thread_id
{
    TF _fn;
    int _thread_id;

    bind_thread_id(TF fn, int thread_id) 
        : _fn(fn), _thread_id(thread_id) 
    { 
    }

    template<typename... Ts>
    auto operator()(Ts&&... xs) 
    {
        // "Bind" `_thread_id` as first argument of `fn`.
        fn(_thread_id, std::forward<Ts>(xs)...);   
    }
};

// ...

threads.push_back(
    std::make_shared <std::thread>(
        bind_thread_id<Fn>{fn, thread_id}, 
        std::forward<Args>(args)...
    )
);