首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++11线程包装函数

C++11线程包装函数
EN

Stack Overflow用户
提问于 2015-10-25 08:32:13
回答 1查看 1.3K关注 0票数 1

我希望有一个包装线程函数,即一个由线程执行的函数,它可以做一些额外的事情,然后调用用户函数。

代码语言:javascript
运行
复制
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
}

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

代码语言:javascript
运行
复制
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)...);
  }

};

这样,线程管理器就应该生成一个使用包装器函数的线程,而包装器函数又会完成额外的工作并调用用户函数。

但是编译器现在说:试图使用已删除的函数.

错误出现在线程头中:

代码语言:javascript
运行
复制
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))...);
}

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

编辑

使用测试:

代码语言:javascript
运行
复制
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 clang3.3上也失败了。

Xcode错误是:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/thread:337:5:错误:尝试使用已删除的函数__invoke(_VSTD::move(_VSTD::get<0>(__t))、_VSTD::move(_VSTD::get<_Indices>(__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 >‘这里请求的int __ec = pthread_create(&__t_,0,&__thread_proxy<_Gp>,__p.get());

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-10-25 15:46:03

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

thread_wrapper的模板参数的拼写方式似乎与std::thread的构造函数不太好--尤其是当它在内部使用简化的std::bind时。完美转发的函数类型和std::decayed函数指针的混合似乎使std::result_of感到不安。

我们可以通过自己在std::decay中应用newThread来实现它:

代码语言:javascript
运行
复制
return std::thread( thread_wrapper<typename std::decay<F>::type,
                                   typename std::decay<Args>::type...>,
                    std::forward<F>(f), 
                    std::forward<Args>(args)... );

老实说,...but,我不完全确定这是为什么。

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

代码语言:javascript
运行
复制
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中使用

代码语言:javascript
运行
复制
return std::thread(wrapper_helper{}, std::forward<F>(f), std::forward<Args>(args)...);

下面是一个完整的示例,显示按值、引用和rvalue引用传递的参数,这些参数按预期工作:http://coliru.stacked-crooked.com/a/b75d5a264f583237

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33327686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档