Search code examples
c++multithreadingc++11stdthread

Invoking a function automatically on std::thread exit in C++11


I want to set up an invocation of a function (or lambda function) to happen automatically when the current thread exits, but I cannot see any way to do it that works with std::thread unless I take over the entire task of thread creation or manually ensure that every thread calls some particular function that I always provide as its very last operation.

Essentially, I want function whose prototype may resemble something like this:

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

Which would perform whatever setup was necessary to ensure that the given function was automatically called when the thread which called on_thread_exit eventually terminates, and without requiring any particular functions to be explicitly called at thread creation or termination.


Solution

  • You can do it using thread_local storage, since C++11 should call the destructors after the thread exits. You'll have to make sure you have a compiler that supports that properly.

    #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));
    }
    

    Basically, this function creates a thread_local object of the above class. This is basically static, except is destroyed when the thread exits. When called, it pushes the function onto the vector, and when its destroyed it runs the functions.

    You can use it by calling on_thread_exit() from any thread, which will create the exit object, which will run your function in the reverse order that it was put into the thread queue (feel free to modify as you see fit).