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

mar*_*964 6 c++ multithreading c++11 stdthread

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

基本上,我想要的功能,其原型可能类似于这样的东西:

on_thread_exit(const std::function<void()> &func);
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*e S 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));
}
Run Code Online (Sandbox Code Playgroud)

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

您可以通过on_thread_exit()从任何线程调用来使用它,该线程将创建退出对象,该对象将按照与放入线程队列相反的顺序运行您的函数(可以根据需要随意修改).


Tho*_*erl 5

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

  • 由于ThreadExiter只使用一次,我们可以组合变量声明,避免public/ private(classto struct)并删除复制构造函数/赋值运算符
  • 替换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));
}
Run Code Online (Sandbox Code Playgroud)