{"id":99385,"date":"2018-08-01T07:00:00","date_gmt":"2018-08-01T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=99385"},"modified":"2019-03-13T00:37:37","modified_gmt":"2019-03-13T07:37:37","slug":"20180801-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20180801-00\/?p=99385","title":{"rendered":"Creating an apartment-aware PPL task from nothing"},"content":{"rendered":"<p>In the Parallel Patterns Library (PPL) of the Concurrency Runtime, there are these things called <code>task<\/code>s. Some tasks are <i>apartment-aware<\/i>, which means that the <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/hh749968.aspx#task_continuation_context::use_default Method\">default continuation context<\/a> will execute the task continuation in the same COM apartment that queued the continuation. Otherwise, the task is not apartment-aware, which means that the default continuation context is <a HREF=\"https:\/\/msdn.microsoft.com\/en-us\/library\/hh749968.aspx#task_continuation_context::use_arbitrary Method\">arbitrary<\/a>: The concurrency runtime will execute the task continuation in a thread of its choosing. <\/p>\n<p>If you are working with objects that have thread affinity, you are operating on a single-threaded apartment (STA), and you need the continuation to run on that same thread so that you still have access to those objects. <\/p>\n<p>The rule used by the Concurrency Runtime is that tasks which are derived from <code>IAsync&shy;Action<\/code> or <code>IAsync&shy;Operation&lt;T&gt;<\/code> are apartment-aware, and others are not. <\/p>\n<p>Okay, so it&#8217;s easy to create a non-apartment-aware completed task. <\/p>\n<pre>\nConcurrency::task&lt;void&gt; completed_non_apartment_aware_task()\n{\n return Concurrency::task_from_result();\n}\n<\/pre>\n<p>There is already a function in the Parallel Patterns Library for creating a completed task, and the result is a non-apartment-aware task. <\/p>\n<p>The hard part is creating an apartment-aware completed task. Here&#8217;s what I came up with: <\/p>\n<pre>\nConcurrency::task&lt;void&gt; completed_apartment_aware_task()\n{\n  Concurrency::create_task(Concurrency::create_async([]{}));\n}\n<\/pre>\n<p>Working from the inside out: We start with a lambda that does nothing. We use <code>create_async<\/code> to wrap that lambda inside an <code>IAsync&shy;Action<\/code>. Then we use <code>create_task<\/code> to wrap the <code>IAsync&shy;Action<\/code> inside a <code>task<\/code>. <\/p>\n<p>It&#8217;s not pretty, but it works. <\/p>\n<p>Now you can write things like <\/p>\n<pre>\n    completed_apartment_aware_task()\n    .then([this]()\n    {\n       \/\/ something\n    }).then([this](int result)\n    {\n       \/\/ something\n    });\n<\/pre>\n<p>and all of the <code>something<\/code>s will run on the same apartment as the code that started the task chain. <\/p>\n<p>This is particularly handy when you want to run a task conditionally on a UI thread. For the branch where you don&#8217;t want a task, you still have to make one, and you want it to be apartment-aware, so that your UI code stays on the UI thread. <\/p>\n<pre>\nConcurrency::task&lt;void&gt; MaybeDoSomethingAsync()\n{\n  if (condition) {\n    return Concurrency::create_task(...);();\n  } else {\n    return completed_apartment_aware_task();\n  }\n}\n<\/pre>\n<p>In the case where the condition is false, you still have to return a task, and you want it to be an apartment-aware task. <\/p>\n<p><b>Bonus chatter<\/b>: This little detour through <code>IAsync&shy;Action<\/code> is necessary only if you are using <code>concurrency::task::then()<\/code> to attach continuations. <\/p>\n<p>If you use <code>co_await<\/code> with <code>Concurrency::task<\/code>, then the <code>pplawait.h<\/code> header file controls how the continuation is scheduled, and it uses <code>task_continuation_context::get_current_winrt_context()<\/code> to schedule the continuation, which means that the task continues in the same apartment. <\/p>\n<p>If you use <code>co_await<\/code> with C++\/winrt, then the continuation runs in the same apartment, although there are special awaitable objects for <a HREF=\"https:\/\/docs.microsoft.com\/en-us\/windows\/uwp\/cpp-and-winrt-apis\/concurrency\">explicitly moving between apartments<\/a>. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>It says it has to be <CODE>IAsync&shy;Action<\/CODE>&#8211; or <CODE>IAync&shy;Operation&lt;T&gt;<\/CODE>-derived, so let&#8217;s do that.<\/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-99385","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It says it has to be <CODE>IAsync&shy;Action<\/CODE>&#8211; or <CODE>IAync&shy;Operation&lt;T&gt;<\/CODE>-derived, so let&#8217;s do that.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/99385","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=99385"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/99385\/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=99385"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=99385"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=99385"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}