在C ++ 11中的std :: thread exit上自动调用函数

时间:2013-11-21 04:04:41

标签: c++ multithreading c++11 stdthread

我想设置一个函数(或lambda函数)的调用,以便在当前线程退出时自动发生,但我看不到任何与std::thread一起使用的方法,除非我接管整个线程创建的任务或手动确保每个线程调用一些我总是提供的特定函数作为它的最后一个操作。

基本上,我想要的原型可能类似于以下内容的函数:

on_thread_exit(const std::function<void()> &func);

当调用on_thread_exit的线程最终终止时,执行必要的设置以确保自动调用给定函数,并且不需要在创建线程或终止时显式调用任何特定函数。

3 个答案:

答案 0 :(得分:20)

你可以使用thread_local存储来实现,因为C ++ 11应该在线程退出后调用析构函数。你必须确保你有一个正确支持它的编译器。

#include <stack> 
#include <function>

void on_thread_exit(std::function<void()> func)
{
  class ThreadExiter
  {
    std::stack<std::function<void()>> exit_funcs;
  public:
    ThreadExiter() = default;
    ThreadExiter(ThreadExiter const&) = delete;
    void operator=(ThreadExiter const&) = delete;
    ~ThreadExiter()
    {
      while(!exit_funcs.empty())
      {
        exit_funcs.top()();
        exit_funcs.pop();
      }
    }
    void add(std::function<void()> func)
    {
      exit_funcs.push(std::move(func));
    }   
  };

  thread_local ThreadExiter exiter;
  exiter.add(std::move(func));
}

基本上,此函数会创建上述类的thread_local对象。这基本上是静态的,除了在线程退出时被销毁。当被调用时,它将函数推送到向量上,当它被破坏时,它会运行函数。

您可以通过从任何线程调用on_thread_exit()来使用它,这将创建退出对象,该对象将以与放入线程队列相反的顺序运行您的函数(随意修改,如您所见适合)。

答案 1 :(得分:5)

这是一个基于Dave S的解决方案的简化/缩短版本,该解决方案使用了更多具有以下属性的C ++ 11功能:

  • 由于ThreadExiter仅使用一次,我们可以合并变量声明,避免public / privateclassstruct)并删除副本构造函数/赋值运算符
  • std::stack替换为基于范围的for循环和std::deque
  • 直接添加到成员变量,而不是使用add()方法

请注意,只有在调用了所有函数对象之后,才会调用std::deque中的回调函数,这可能是也可能不是你想要的 - 如果你需要在函数对象被调用后销毁它(在调用任何其他函数对象之前,使用像Dave的解决方案中的堆栈和弹出元素。

代码:

#include <functional>
#include <deque>

void
on_thread_exit(std::function<void()> func)
{
    thread_local struct ThreadExiter {
        std::deque<std::function<void()>> callbacks;

        ~ThreadExiter() {
            for (auto &callback: callbacks) {
                callback();
            }
        }
    } exiter;

    exiter.callbacks.emplace_front(std::move(func));
}

答案 2 :(得分:1)

您可以使用BOOST_SCOPE_EXIT

对于主线程:

void on_thread_exit();

void main( int argc, char** argv )
{
   BOOST_SCOPE_EXIT() // may be one arg, at least, is required 
   {
      on_thread_exit();
   }BOOST_SCOPE_EXIT_END

   ...
}

我让你去推断任何线程!