{"id":9692,"date":"2024-07-01T10:12:43","date_gmt":"2024-07-01T10:12:43","guid":{"rendered":"https:\/\/www.modernescpp.com\/?p=9692"},"modified":"2024-07-01T10:12:44","modified_gmt":"2024-07-01T10:12:44","slug":"cooperative-interruption-of-a-thread-in-c20","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/cooperative-interruption-of-a-thread-in-c20\/","title":{"rendered":"Cooperative Interruption of a Thread in C++20"},"content":{"rendered":"<p>A typical question in my C++ seminars is: Can a\u00a0 thread be killed? Before C++20, my answer is no. With C++20, you can ask a thread politely for its interruption.<\/p>\n<p><!--more--><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6079\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Interruption.png\" alt=\"TimelineCpp20Interruption\" width=\"650\" height=\"229\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Interruption.png 912w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Interruption-300x106.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/TimelineCpp20Interruption-768x270.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>First of all. Why is it not a good idea to kill a thread? The answer is relatively easy. You don&#8217;t know which state the thread is in when you kill it. Here are two possible malicious outcomes.<\/p>\n<ul>\n<li>The thread is only half-done with its job. Consequently, you don&#8217;t know the state of that job and, hence, the state of your program. You end with undefined behavior, and all bets are open.<\/li>\n<li>The thread may be in a critical section and locks a mutex. Killing a thread while it locks a mutex ends with a high probability of deadlock.<\/li>\n<\/ul>\n<p>Okay, killing a thread is not a good idea. You may ask a thread friendly if it is willing to stop. This is precisely what cooperative interruption in C++20 means. You ask the thread, and the thread can accept or ignore your wish for the interruption.<\/p>\n<h2>Cooperative Interruption<\/h2>\n<p>The additional functionality of the cooperative interruption thread in C++20 is based on the <code>std::stop_token<\/code>, the <code>std::stop_callback<\/code>, and the <code>std::stop_source<\/code>\u00a0data types.<\/p>\n<h3><code>std::stop_token<\/code>, <code>std::stop_callback<\/code>, and <code>std::stop_source<\/code><\/h3>\n<p>A <code>std::stop_token<\/code>, a<code> std::stop_callback<\/code>, or a <code>std::stop_source<\/code>\u00a0allows a thread to asynchronously request an execution to stop or ask if an execution got a stop signal. The <code>std::stop_token<\/code> can be passed to an operation and afterward be used to poll the token for a stop request actively or to register a callback via <code>std::stop_callback<\/code>. The stop request is sent by a <code>std::stop_source<\/code>. This signal affects all associated<code> std::stop_token<\/code>. The three classes <code>std::stop_source<\/code>, <code>std::stop_token<\/code>, and <code>std::stop_callback<\/code>\u00a0share the ownership of an associated stop state. The calls <code>request_stop()<\/code>, <code>stop_requested()<\/code>, and <code>stop_possible()<\/code> are atomic.<\/p>\n<p>You can construct a <code>std::stop_source<\/code> in two ways:<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">stop_source();                                      <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n<span style=\"color: #006699; font-weight: bold;\">explicit<\/span> stop_source(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">nostopstate_t<\/span>) noexcept;  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n<\/pre>\n<\/div>\n<p>The default constructor (1) constructs a <code>std::stop_source<\/code> with a new stop state. The constructor taking<code> std::nostopstate_t<\/code> (2) constructs an empty<code> std::stop_source<\/code> without associated stop state.<br \/>\nThe component\u00a0<code>std::stop_source src<\/code>\u00a0provides the following member functions for handling stop requests.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6080\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopSource.png\" alt=\"stopSource\" width=\"650\" height=\"208\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopSource.png 1186w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopSource-300x96.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopSource-1024x328.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopSource-768x246.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p><code>src.stop_possible()<\/code> means that<code> src<\/code> has an associated stop state. <code>src.stop_requested()<\/code> returns <code>true<\/code> when <code>src<\/code> has an associated stop state and was not asked to stop earlier. <code>src.request_stop()<\/code> is successful and returns <code>true<\/code> if <code>src<\/code> has an associated stop state, which was not requested to stop before.<\/p>\n<p>The call <code>src.get_token()<\/code> returns the stop token<code> stoken<\/code>. Thanks to <code>stoken<\/code> you can check if a stop requ<\/p>\n<p>est has been made or can be made for its associated stop source <code>src<\/code>. The stop token <code>stoken<\/code> observes the stop source <code>src<\/code>.<\/p>\n<p>The following table presents the member functions of a <code>std::stop_token stoken<\/code>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6081\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopToken.png\" alt=\"stopToken\" width=\"650\" height=\"127\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopToken.png 1158w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopToken-300x59.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopToken-1024x200.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/stopToken-768x150.png 768w\" sizes=\"auto, (max-width: 650px) 100vw, 650px\" \/><\/p>\n<p>A default-constructed token that has no associated stop state.<code> stoken.stop_possible<\/code> also returns <code>true<\/code> if <code>stoken<\/code> has an associated stop state.\u00a0<code>stoken.stop_requested()<\/code> returns <code>true<\/code> when the stop token has an associated stop state and has already received a stop request.<\/p>\n<p>If the <code>std::stop_token<\/code> should be temporarily disabled, you can replace it with a default constructed token. A default constructed token has no associated stop-state. The following code snippet shows how to disable and enable a thread&#8217;s capability to accept stop requests.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\">std<span style=\"color: #555555;\">::<\/span>jthread jthr([](std<span style=\"color: #555555;\">::<\/span>stop_token stoken) {\n    ...\n    std<span style=\"color: #555555;\">::<\/span>stop_token interruptDisabled;\n    std<span style=\"color: #555555;\">::<\/span>swap(stoken, interruptDisabled);  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n    ...                                    <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n    std<span style=\"color: #555555;\">::<\/span>swap(stoken, interruptDisabled);\n    ...\n}\n<\/pre>\n<\/div>\n<p><code>std::stop_token interruptDisabled<\/code> has no associated stop state. This means the thread<code> jthr<\/code> can, in all lines except lines (1) and (2), accept stop requests.<\/p>\n<p>When you study the code snippet carefully, you may wonder if the used <code>std::jthread. std::jthread<\/code> in C++20 is an extended <code>std::thread<\/code> in C++11. The <strong>j<\/strong> in <code>jthread<\/code> stands for joinable because it joins automatically in its destructor. Its first name was <code>ithread<\/code>. You may guess why: <strong>i<\/strong> stands for interruptible. I will present <code>std::jthread<\/code> in my next post.<\/p>\n<p>My next example shows the use of callbacks using a <code>std::jthread.<\/code><\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ invokeCallback.cpp<\/span>\n\n<span style=\"color: #009999;\">#include &lt;chrono&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\n\n<span style=\"color: #006699; font-weight: bold;\">using<\/span> <span style=\"color: #006699; font-weight: bold;\">namespace<\/span><span style=\"color: #555555;\">::<\/span>std<span style=\"color: #555555;\">::<\/span>literals;\n\n<span style=\"color: #006699; font-weight: bold;\">auto<\/span> func <span style=\"color: #555555;\">=<\/span> [](std<span style=\"color: #555555;\">::<\/span>stop_token stoken) {                             <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\n        <span style=\"color: #007788; font-weight: bold;\">int<\/span> counter{<span style=\"color: #ff6600;\">0<\/span>};\n        <span style=\"color: #006699; font-weight: bold;\">auto<\/span> thread_id <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id();\n        std<span style=\"color: #555555;\">::<\/span>stop_callback callBack(stoken, [<span style=\"color: #555555;\">&amp;<\/span>counter, thread_id] {  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\n            std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"Thread id: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> thread_id \n                      <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"; counter: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> counter <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\n        });\n        <span style=\"color: #006699; font-weight: bold;\">while<\/span> (counter <span style=\"color: #555555;\">&lt;<\/span> <span style=\"color: #ff6600;\">10<\/span>) {\n            std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">0.2<\/span>s);\n            <span style=\"color: #555555;\">++<\/span>counter;\n        }\n    };\n\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>() {\n    \n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\n    \n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span>std<span style=\"color: #555555;\">::<\/span>jthread<span style=\"color: #555555;\">&gt;<\/span> vecThreads(<span style=\"color: #ff6600;\">10<\/span>);\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span>(<span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> thr<span style=\"color: #555555;\">:<\/span> vecThreads) thr <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>jthread(func);\n    \n    std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>sleep_for(<span style=\"color: #ff6600;\">1<\/span>s);                              <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\n    \n    <span style=\"color: #006699; font-weight: bold;\">for<\/span>(<span style=\"color: #006699; font-weight: bold;\">auto<\/span><span style=\"color: #555555;\">&amp;<\/span> thr<span style=\"color: #555555;\">:<\/span> vecThreads) thr.request_stop();                <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\n\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">'\\n'<\/span>;\n    \n}\n<\/pre>\n<\/div>\n<p>Each of the ten threads invokes the lambda function<code> func<\/code> (1). The callback (2) displays the thread <code>id<\/code> and the <code>counter<\/code>. Due to the one-second sleeping of the main thread (3) and the sleeping of the child threads, the counter is 4 when the callbacks are invoked. The call <code>thr.request_stop()<\/code> triggers the callback on each thread.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-6082\" style=\"display: block; margin-left: auto; margin-right: auto;\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/invokeCallback.png\" alt=\"invokeCallback\" width=\"500\" height=\"347\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/invokeCallback.png 842w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/invokeCallback-300x208.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2021\/02\/invokeCallback-768x533.png 768w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>As mentioned,\u00a0 <code>std::thread<\/code> has one significant weakness. When you forget to join it, its destructor calls <code>std::terminate<\/code>, and your program crashes. <code>std::jthread<\/code> (C++20) overcomes this counter-intuitive weakness and is also interruptible.<\/p>\n<h2>Repetition<\/h2>\n<p>You may have noticed it. This post is a repetition of a post I have written 3 1\/2 years ago. The reason is simple. I need this post as a prerequisite for my next post, and I don&#8217;t want to write a post two times.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A typical question in my C++ seminars is: Can a\u00a0 thread be killed? Before C++20, my answer is no. With C++20, you can ask a thread politely for its interruption.<\/p>\n","protected":false},"author":21,"featured_media":6079,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[375],"tags":[448],"class_list":["post-9692","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-20","tag-jthread"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/9692","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=9692"}],"version-history":[{"count":2,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/9692\/revisions"}],"predecessor-version":[{"id":9716,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/9692\/revisions\/9716"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/6079"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=9692"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=9692"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=9692"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}