This article is a repeat of a post I originally wrote three and a half years ago. I need this as a starter for the next article. So, I decided to republish the post.
Advertisement
Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages ​​C++, Python and Haskell, but also frequently speaking at specialist conferences. On his blog Modern C++ he discusses his passion C++ in depth.
First, why is it not a good idea to terminate a thread? The answer is simple. You don’t know what state the thread is in when you terminate it. There are two potential dangers:
- The threads may finish their job only partially. Of course, the state of their job and hence the state of the program is now unknown. Ultimately, this leads to undefined behavior and no reliable statements about the program are possible anymore.
- The thread may currently be in a critical region and the mutex may be locked. If the thread terminates in this stage, it will likely cause a deadlock.
It’s not a good idea to abruptly interrupt a thread. It’s better to ask politely if you want the thread to terminate. This is what cooperative breaking means in C++20. You politely ask the thread if it wants to terminate, and the thread can either honor your request or ignore it.
Collaborative disruption
Additional cooperative break capability in C++20 based on three new data types std::stop_token
, std::stop_callback
And std::stop_source
. They allow a thread to terminate a thread asynchronously or ask whether the thread has received a stop signal. std::stop_toke
n
can be assigned to an operation for this purpose. This stop token can be used to ask the operation if a request to terminate has been sent to it. On the other hand, you can std::stop_token
Using a callback std::stop_callback
be recorded. The stop request is made by std::stop_source
Sent. Your signal affects all affiliates std::stop_token
. Three classes std::stop_source
, std::stop_token
And std::stop_callback
Share ownership of the related stop position. Call request_stop()
, stop_requested()
And stop_possible()
There are atoms.
A std::stop_source
Can be made in two ways:
stop_source(); // (1)
explicit stop_source(std::nostopstate_t) noexcept; // (2)
Creates a default constructor (1) std::stop_source
with stopping condition. Manufacturer, std::nostopstate_t
takes as an argument generates a std::stop_source
without an associated stop condition.
Constituent std::stop_source src
Provides the following methods for handling stop requests:

src.stop_possible()
means that src
There is an associated stop condition. src.stop_requested()
then gives it again true
back if src
There is an associated stop condition and it has not been requested to stop before. Call src.get_token()
Returns the stop token. Thanks to it, you can check whether a stop request has already been made or can be made.
Stop Token stoken
Stops inspecting the source src
. The following table presents the methods std::stop_token stoken
First:
Default-constructed tokens have no associated stop conditions. stoken.stop_possible
gives true
back if stoken
There is an associated stop condition. stoken_stop_requested()
then gives it again true
This is returned if the stop token has an associated stop status and has already received a stop request.
If std::stop_token
If you want to temporarily disable it, it can be replaced with a default-constructed token. It has no associated stop state. The following lines show how to temporarily disable the thread’s ability to receive stop requests:
std::jthread jthr(()(std::stop_token stoken) {
...
std::stop_token interruptDisabled;
std::swap(stoken, interruptDisabled); // (1)
... // (2)
std::swap(stoken, interruptDisabled);
...
}
std::stop_token
interruptDisabled
There is no associated stop condition. i.e. the thread jthr
All lines except (1) and (2) can accept stop requests.
If you study the code snippet carefully, you will be fine std::jthread
But. std::jthread
C++20 has an extended std::thread
From C++11. In “J” jthread
stands for joinableBecause one std::jthread
automatically combined into its destructor. Originally this new formula was called ithread
: “I” means disruptive. I put std::jthread
In more detail in the next article.
The next example shows how std::jthread
Can be used together with callbacks:
// invokeCallback.cpp
#include
#include
#include
#include
using namespace::std::literals;
auto func = ()(std::stop_token stoken) { // (1)
int counter{0};
auto thread_id = std::this_thread::get_id();
std::stop_callback callBack(stoken, (&counter, thread_id) // (2)
{
std::cout << "Thread id: " << thread_id
<< "; counter: " << counter << '\n';
});
while (counter < 10) {
std::this_thread::sleep_for(0.2s);
++counter;
}
};
int main() {
std::cout << '\n';
std::vector<:jthread> vecThreads(10);
for(auto& thr: vecThreads) thr = std::jthread(func);
std::this_thread::sleep_for(1s); // (3)
for(auto& thr: vecThreads) thr.request_stop(); // (4)
std::cout << '\n';
}
Each of the ten threads calls the lambda function func
(1) on the callback (2) representing the ID of the thread and the counter, thanks to a one second sleep main
Thread (3) and child thread are sleeping, value of counter is 4 at the time of callback call thr.request_stop()
(4) Initiates a callback on each thread.
(RME)
