9

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

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

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

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

4

3 回答 3

23

您可以使用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()从任何线程调用它来使用它,这将创建出口对象,该对象将以与放入线程队列的相反顺序运行您的函数(随意修改您认为合适的)。

于 2013-11-21T04:40:33.147 回答
6

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

  • 由于ThreadExiter只使用一次,我们可以结合变量声明,避免public/ private( classto struct) 并移除复制构造函数/赋值运算符
  • 替换std::stack为基于范围的 for 循环和std::deque
  • 直接添加到成员变量中,而不是有一个add()方法

请注意,这会破坏回调函数std::deque,这可能是您想要的,也可能不是您想要的——如果您需要在调用函数对象之后(以及在调用任何其他函数对象之前)将其销毁),使用堆栈和弹出元素,如戴夫的解决方案)。

代码:

#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));
}
于 2017-04-25T10:03:51.453 回答
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

   ...
}

我让你推断任何线程!

于 2013-11-21T08:30:33.533 回答