{"id":103997,"date":"2020-07-22T07:00:00","date_gmt":"2020-07-22T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103997"},"modified":"2020-07-22T07:40:45","modified_gmt":"2020-07-22T14:40:45","slug":"20200722-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200722-00\/?p=103997","title":{"rendered":"How to get your C++\/WinRT asynchronous operations to respond more quickly to cancellation, part 1"},"content":{"rendered":"<p>C++\/WinRT provides an implementation for Windows Runtime asynchronous actions and operations, and they even support cancellation, even if your code doesn&#8217;t realize it.<\/p>\n<p>Whenever\u00b9 your coroutine performs a <code>co_await<\/code>, the C++\/WinRT library checks whether the coroutine has already been cancelled.\u00b2 If so, then it abandons the coroutine and goes to the <code>Canceled<\/code> state.<\/p>\n<pre>IAsyncAction ProcessAllWidgetsAsync()\r\n{\r\n    auto widgets = co_await GetAllWidgetsAsync();\r\n    for (auto&amp;&amp; widget : widgets) {\r\n        ProcessWidget(widget);\r\n    }\r\n    co_await ReportStatusAsync(WidgetsProcessed);\r\n}\r\n<\/pre>\n<p>This function gathers all the widgets and then processes them one by one. But say there are thousands of widgets, and you try to <code>Cancel<\/code> the operation:<\/p>\n<pre>IAsyncAction DoOperationAsync()\r\n{\r\n    \/\/ Remember the operation so we can cancel it.\r\n    operation = ProcessAllWidgetsAsync();\r\n\r\n    co_await operation;\r\n}\r\n\r\nvoid CancelOperation()\r\n{\r\n    operation.Cancel();\r\n}\r\n<\/pre>\n<p>When the <code>Cancel<\/code> is called, the C++\/WinRT library remembers that the coroutine has been cancelled and looks for a chance to stop the coroutine. But right now, the coroutine is busy running the loop inside <code>Process\u00adAll\u00adWidgets<\/code>, and the C++\/WinRT library doesn&#8217;t get control until the <code>co_await<\/code> when it comes time to report the status. Once that happens, the coroutine stops executing and reports its cancellation.\u00b3<\/p>\n<p>That could be hours from now.<\/p>\n<p>You can hasten the cancellation process in your coroutine by polling for cancellation.<\/p>\n<pre>IAsyncAction ProcessAllWidgetsAsync()\r\n{\r\n    <span style=\"color: blue;\">auto cancellation = co_await get_cancellation_token();<\/span>\r\n\r\n    auto widgets = co_await GetAllWidgetsAsync();\r\n    for (auto&amp;&amp; widget : widgets) {\r\n        <span style=\"color: blue;\">if (cancellation()) co_return;<\/span>\r\n        ProcessWidget(widget);\r\n    }\r\n    co_await ReportStatusAsync(WidgetsProcessed);\r\n}\r\n<\/pre>\n<p>The <code>co_await get_<wbr \/>cancellation_<wbr \/>token()<\/code> produces a cancellation token for the current coroutine.\u2074<\/p>\n<p>Before processing each widget, we check if we have been cancelled. If so, then we just give up immediately. The <code>co_return<\/code> is another point where the C++\/WinRT library regains control, and that also processes the pending cancellation.<\/p>\n<p>But wait, what if the caller tries to cancel the operation while the <code>Get\u00adAll\u00adWidgets\u00adAsync<\/code> is in progress? Control is now inside that other asynchronous operation, and it could take a very long time to get all of the widgets. Next time, we&#8217;ll look at how to propagate the cancellation into dependent coroutines.<\/p>\n<p>\u00b9 There are a few exceptions to this rule, but it&#8217;s true enough.<\/p>\n<p>\u00b2 I spell <i>cancelled<\/i> with two L&#8217;s.<\/p>\n<p>\u00b3 This highlights the importance of using RAII types for all of your cleanup. If the coroutine stops executing due to cancellation, then its automatic objects are destructed according to the usual rules of C++, and that&#8217;s where your abnormal cleanup happens. We&#8217;ll talk more about this soon.<\/p>\n<p>\u2074 The <code>co_await get_<wbr \/>cancellation_<wbr \/>token()<\/code> is one of the exceptions to the rule that <code>co_await<\/code> always checks for cancellation. In this case, <code>co_await get_<wbr \/>cancellation_<wbr \/>token()<\/code> doesn&#8217;t actually &#8220;await&#8221; anything. Rather, it&#8217;s a backdoor into the C++\/WinRT library. We&#8217;ll learn more about how these backdoors work when we look at how to implement your own coroutines in C++20, at some unspecified point in the future.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Well, one way is to poll for it.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103997","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Well, one way is to poll for it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103997","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103997"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103997\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103997"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103997"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103997"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}