C ++ 11线程包装函数

时间:2015-10-25 08:32:14

标签: multithreading c++11

我想要一个包装线程函数,即由执行一些额外操作的线程执行的函数,然后调用用户函数。

template<class F, class... Args>
void wrapper(F&& user_function, Args&&... args) {
  // do some extra stuff
  user_function(args); // maybe I need to forward args
  // do some extra stuff
}

好吧,这可能是一个很好的包装器,所以我需要一个使用这个包装器函数的管理器,并允许用户生成自己的线程:

class ThreadManager {
public:

  template<class F, class... Args>
  std::thread newThread(F&& f, Args&&... args) {
    return std::thread(thread_wrapper<F,Args...>, std::forward<F>(f), std::forward<Args>(args)...);
  }

};

这样线程管理器应该产生一个使用包装器函数的线程,而该包装函数反过来做额外的工作并调用用户函数。

但编译器现在说:尝试使用已删除的功能。

错误在线程头中:

template <class _Fp, class ..._Args, size_t ..._Indices>
inline _LIBCPP_INLINE_VISIBILITY
void
__thread_execute(tuple<_Fp, _Args...>& __t, __tuple_indices<_Indices...>)
{
    __invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...);
}

我错过了什么/做错了什么?

[编辑]

使用测试:

void foo(int i) {
  std::cout << "foo: " << i << std::endl;
}

int main(int argc, const char *argv[]) {
  ThreadManager mgr;
  auto t = mgr.newThread(foo, 10);
  t.detach();

  std::this_thread::sleep_for(std::chrono::milliseconds(1000));

  return 0;
}

我正在使用带有LLVM编译器的Xcode 7.1,但在FreeBSD clang 3.3上也失败了。

Xcode错误是:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin /../ include / c ++ / v1 / thread:337:5:错误:尝试使用已删除的功能     __invoke(_VSTD :: move(_VSTD :: get&lt; 0&gt;(__ t)),_ VSTD :: move(_VSTD :: get&lt; _Indices&gt;(__ t))...);     ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:347:5:注意:在实例化函数模板特化'std :: __ 1: :__ thread_execute'在这里请求     __thread_execute(* __ p,_Index());     ^ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:359:42:注意:在实例化函数模板特化'std :: __ 1: :__ thread_proxy&gt;'这里要求     int __ec = pthread_create(&amp; __ t_,0,&amp; __ thread_proxy&lt; _Gp&gt;,__ p.get());

1 个答案:

答案 0 :(得分:1)

我不确定在您的示例中导致“尝试使用已删除的函数”的原因是什么,我得到与std::thread的绑定机制相关的其他错误。

看起来你拼出thread_wrapper的模板参数的方式与std::thread的构造函数没有关系 - 特别是当它在内部使用简化的std::bind时。完美转发的函数类型和std::decay ed函数指针的混合似乎扰乱了std::result_of

我们可以通过在std::decay中自行应用newThread来使其工作:

return std::thread( thread_wrapper<typename std::decay<F>::type,
                                   typename std::decay<Args>::type...>,
                    std::forward<F>(f), 
                    std::forward<Args>(args)... );

...但说实话,我并不完全确定为什么有效。

或者,通过一些间接和更多转发,我们可以避免拼出模板参数。 我们只需要一个转发到thread_wrapper(或C ++ 14中的多态lambda)的仿函数:

struct wrapper_helper {
    template<class F, class... Args>
    void operator()(F&& f, Args&&... args) const {
        thread_wrapper(std::forward<F>(f), std::forward<Args>(args)...);
    }
};

并在newThread

中使用它
return std::thread(wrapper_helper{}, std::forward<F>(f), std::forward<Args>(args)...);

以下是显示按值,参考和右值引用传递的参数的完整示例:http://coliru.stacked-crooked.com/a/b75d5a264f583237

注意:对于仅std::unique_ptr这样的仅限移动类型,您肯定希望在args...转发thread_wrapper