Function call automatically on std :: thread exit in C ++ 11

I want to configure a function call (or lambda function) that will be executed automatically when the current thread exits, but I see no way to do this that works with std::thread unless I take on the whole task of creating a thread or manually ensure that each thread invokes a specific function that I always provide as the most recent operation.

Essentially, I want a function whose prototype might look something like this:

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

To make any adjustments to ensure that this function was automatically called when the thread that called on_thread_exit ultimately terminated, and without requiring any specific functions to be explicitly called when the thread was created or terminated.

+6
source share
3 answers

You can do this with the thread_local repository, since C ++ 11 should call destructors after the thread exits. You must make sure that you have the appropriate compiler.

 #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 specified class. This is mostly static, except that it is destroyed when the stream exits. When it is called, it pushes the function onto the vector, and when it destroys it, it performs the functions.

You can use it by calling on_thread_exit() from any thread that will create an exit object that will run your function in the reverse order so that it is placed in the thread queue (feel free to modify as you like).

+19
source

Here is a simplified / abridged version based on the Dave S solution, which uses more features of C ++ 11 with the following properties:

  • Since ThreadExiter used only once, we can combine the variable declaration, avoid public / private ( class to struct ) and delete the copy constructor / assignment operator
  • Replace std::stack based on range for loop and std::deque
  • Add to the member variable directly instead of the add() method

Note that this destroys the callback functions from std::deque only after everyone has been called, which may or may not be what you want - if you need to destroy the function object after calling it (and before any other objects functions), use the stack and pop elements, for example, in the Dave solution).

code:

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

You can use BOOST_SCOPE_EXIT

For the main thread:

 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 ... } 

I leave you to extrapolate any stream!

+1
source

Source: https://habr.com/ru/post/958532/


All Articles