{"id":11821,"date":"2025-11-30T21:19:44","date_gmt":"2025-11-30T21:19:44","guid":{"rendered":"https:\/\/putridparrot.com\/blog\/?p=11821"},"modified":"2025-11-30T21:20:42","modified_gmt":"2025-11-30T21:20:42","slug":"cancellation-tokens-in-rust","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/cancellation-tokens-in-rust\/","title":{"rendered":"Cancellation tokens in Rust"},"content":{"rendered":"<p>When using tokio::spawn we might wish to pass through a cancellation token to allow us to cancel a long running thread.<\/p>\n<p>We can create a cancellation token like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nlet token = CancellationToken::new();\r\n<\/pre>\n<p>From this we could take one or more child tokens like this<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nlet child = token.child_token();\r\n<\/pre>\n<p>Using child token&#8217;s allows us to cancel all child tokens from the parent or we can cancel each one individually<\/p>\n<p>Now if we spawn our threads, in this case we&#8217;ll create two concurrent branches. The first one that completes is the returning value. In this instance we&#8217;ll store the JoinHandle just to allow us to force the application to wait upon completion so we get something meaningful output to the console<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nlet handle = tokio::spawn(async move {\r\n  tokio::select! {\r\n    _ = child.cancelled() =&gt; {\r\n      println!(&quot;Child1 task cancelled&quot;);\r\n    }\r\n    _ = tokio::time::sleep(Duration::from_secs(30)) =&gt; {\r\n      println!(&quot;Child2 task cancelled&quot;);\r\n    }\r\n  }\r\n});\r\n<\/pre>\n<p>Here&#8217;s the full code, starting with cargo.toml dependencies<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;dependencies]\r\ntokio-util = &quot;0.7.17&quot;\r\ntokio = { version = &quot;1.48.0&quot;, features = &#x5B;&quot;rt&quot;, &quot;rt-multi-thread&quot;, &quot;macros&quot;, &quot;time&quot;] }\r\nselect = &quot;0.6.1&quot;\r\nanyhow = &quot;1.0.100&quot;\r\n<\/pre>\n<p>Now the main.rs code<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nuse std::io;\r\nuse std::time::Duration;\r\nuse tokio_util::sync::CancellationToken;\r\n\r\n#&#x5B;tokio::main]\r\nasync fn main() -&gt; anyhow::Result&lt;()&gt; {\r\n    let token = CancellationToken::new();\r\n    let child = token.child_token();\r\n\r\n    let handle = tokio::spawn(async move {\r\n        tokio::select! {\r\n            _ = child.cancelled() =&gt; {\r\n                println!(&quot;Child1 task cancelled&quot;);\r\n            }\r\n            _ = tokio::time::sleep(Duration::from_secs(30)) =&gt; {\r\n                println!(&quot;Child2 task cancelled&quot;);\r\n            }\r\n        }\r\n    });\r\n\r\n    io::stdin().read_line(&amp;mut String::new())?;\r\n    token.cancel();\r\n\r\n    handle.await.expect(&quot;Task panicked&quot;);\r\n    println!(&quot;Task Completed&quot;);\r\n\r\n    Ok(())\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>When using tokio::spawn we might wish to pass through a cancellation token to allow us to cancel a long running thread. We can create a cancellation token like this let token = CancellationToken::new(); From this we could take one or more child tokens like this let child = token.child_token(); Using child token&#8217;s allows us to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[191],"tags":[],"class_list":["post-11821","post","type-post","status-publish","format-standard","hentry","category-rust"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11821","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=11821"}],"version-history":[{"count":3,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11821\/revisions"}],"predecessor-version":[{"id":12058,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/11821\/revisions\/12058"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=11821"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=11821"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=11821"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}