Generally, we have to control std::thread‘s life cycle by writting join/detach manually, but actually RAII can help to do it perfectly. Fortuantely, we can achieve it by using std::jthread in C++20 standard library.
std::jthread
The implementation of std::jthread shown in this page is from MSVC STL.
jthread& operator=(jthread&& _Other) noexcept { // note: the standard specifically disallows making self-move-assignment a no-op here // N4861 [thread.jthread.cons]/13 // Effects: If joinable() is true, calls request_stop() and then join(). Assigns the state // of x to *this and sets x to a default constructed state. _Try_cancel_and_join(); _Impl = _STD move(_Other._Impl); _Ssource = _STD move(_Other._Ssource); return *this; }
std::jthread looks basically similar to std::thread. It identifies the thread state by joinable() and adjusts the thread state by join(). In addition to this, we cann’t ignore the member variable _Ssource whose type is stop_source. What is it?
struct_Stop_state { atomic<uint32_t> _Stop_tokens = 1; // plus one shared by all stop_sources atomic<uint32_t> _Stop_sources = 2; // plus the low order bit is the stop requested bit _Locked_pointer<_Stop_callback_base> _Callbacks; // always uses relaxed operations; ordering provided by the _Callbacks lock // (atomic just to get wait/notify support) atomic<const _Stop_callback_base*> _Current_callback = nullptr; _Thrd_id_t _Stopping_thread = 0;
_Callbacks._Store_and_unlock(_Next); // unlock before running _Head so other registrations // can detach without blocking on the callback
_Head->_Fn(_Head); // might destroy *_Head } } };
Usage of std::jthread
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#include<thread>
intmain(){ std::jthread thread([](std::stop_token st) { int i = 0; while (!st.stop_requested()) { std::cout << i++ << std::endl; std::this_thread::sleep_for(std::chrono::seconds(1)); } });
std::this_thread::sleep_for(std::chrono::seconds(5)); // `request_stop()` will be called when thread's dustruction // So its explicit call can be omitted thread.request_stop();