{"id":1901,"date":"2014-02-10T13:00:26","date_gmt":"2014-02-10T13:00:26","guid":{"rendered":"http:\/\/writeasync.net\/?p=1901"},"modified":"2014-02-10T10:00:36","modified_gmt":"2014-02-10T10:00:36","slug":"async-in-c-with-the-ppl","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=1901","title":{"rendered":"Async in C++ with the PPL"},"content":{"rendered":"<p>The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd492418.aspx\">Parallel Patterns Library (PPL)<\/a> provides C++ developers with some very useful concurrency primitives along similar lines as Task parallelism in .NET. Having been <a href=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2009\/01\/12\/an-introduction-to-native-concurrency-in-visual-studio-2010.aspx\">introduced in Visual Studio 2010<\/a>, the PPL is not new by any means. However, it remains relatively obscure to many who dabble in native code.<\/p>\n<p>Similar to .NET, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh750113.aspx\"><code>task&lt;T&gt;<\/code><\/a> is the main star of the native async show. In contrast to C#, C++ allows the use of <code>void<\/code> as a template parameter, so you can pass around <code>task&lt;void&gt;<\/code> instances.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/ MyAsyncWorker.h\r\n#include &lt;ppltasks.h&gt;\r\n\r\nclass MyAsyncWorker\r\n{\r\npublic:\r\n\/\/ ...\r\n    concurrency::task&lt;void&gt; DoWorkAsync();\r\n    concurrency::task&lt;int&gt; DoWorkWithResultAsync();\r\n};\r\n\r\n\/\/ Main.cpp\r\n#include &quot;MyAsyncWorker.h&quot;\r\n\r\nusing namespace concurrency;\r\n\r\n\/\/ ...\r\nMyAsyncWorker w;\r\ntask&lt;void&gt; t1 = w.DoWorkAsync();\r\n\r\n\/\/ does not return anything, but will throw if task has failed.\r\nt1.get();\r\n\r\ntask&lt;int&gt; t2 = w.DoWorkWithResultAsync();\r\n\r\n\/\/ Returns value or throws if task has failed.\r\nint v = t2.get();\r\n\r\n\/\/ ...\r\n<\/pre>\n<p>The PPL equivalent to <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd449174(v=vs.110).aspx\"><code>TaskCompletionSource<\/code><\/a> is <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh750136.aspx\"><code>task_completion_event<\/code><\/a>. The API should look reasonably familiar, though note that there are no <code>Try...<\/code> methods &#8212; instead the <code>set...<\/code> methods all return <code>bool<\/code> to indicate status. To set an exception, <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dn535523.aspx\"><code>std::exception_ptr<\/code><\/a> is used; see the MSDN article <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd293602.aspx\">&#8220;Transporting Exceptions Between Threads&#8221;<\/a> for more details.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\/\/ MyAsyncWorker.cpp\r\ntask&lt;void&gt; MyAsyncWorker::DoWorkAsync()\r\n{\r\n    task_completion_event&lt;void&gt; tce;\r\n\r\n    \/\/ schedule some background work somehow...\r\n    StartBackgroundWork(tce);\r\n\r\n    \/\/ There is no 'get_task' method; instead create a task from the TCE instance\r\n    return task&lt;void&gt;(tce);\r\n}\r\n\r\n\/\/ ...\r\nvoid OnWorkCompleted(task_completion_event&lt;void&gt; tce)\r\n{\r\n    \/\/ Note that the set method for &lt;void&gt; takes no params\r\n    tce.set();\r\n}\r\n\r\nvoid OnWorkFailed(task_completion_event&lt;void&gt; tce, int errorCode)\r\n{\r\n    \/\/ Make an exception_ptr from our custom exception instance\r\n    tce.set_exception(make_exception_ptr(worker_error(errorCode)));\r\n}\r\n<\/pre>\n<p>As far as continuations go, the PPL is about on par with .NET 4.0 &#8212; that is, you won&#8217;t get much compiler code generation help or the niceties of <code>async<\/code>\/<code>await<\/code>. You&#8217;ll have to make do with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh750044.aspx\"><code>then<\/code><\/a>, the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.tasks.task.continuewith(v=vs.110).aspx\"><code>ContinueWith<\/code><\/a> equivalent. Here is an example of a multi-step async method using an imaginary pipe\/buffer API. Note the use of <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb982026.aspx\"><code>std::shared_ptr<\/code><\/a> to manage heap objects so that they don&#8217;t go out of scope prematurely.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ntask&lt;bool&gt; ReadAndWriteAsync(Pipe &amp; input, Pipe &amp; output)\r\n{\r\n    shared_ptr&lt;Buffer&gt; buffer = make_shared&lt;Buffer&gt;();\r\n    return input.ReadAsync(*buffer).then(&#x5B;buffer, &amp;output](task&lt;unsigned int&gt; t1)\r\n    {\r\n        unsigned int bytesRead = t1.get();\r\n        if (bytesRead == 0)\r\n        {\r\n            return task_from_result(false);\r\n        }\r\n\r\n        return output.WriteAsync(*buffer).then(&#x5B;](task&lt;unsigned int&gt; t2)\r\n        {\r\n            unsigned int bytesWritten = t2.get();\r\n            return bytesWritten &gt; 0;\r\n        });\r\n    });\r\n}\r\n<\/pre>\n<p>There is no <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.tasks.task.delay(v=vs.110).aspx\"><code>Task.Delay<\/code><\/a> in the PPL. Instead, you need to use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd492468.aspx\"><code>timer<\/code><\/a> to set a <code>task_completion_event<\/code> after a certain timeout. There is a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh873170.aspx\">sample covering this on MSDN<\/a>, but it is far easier to pick up the <a href=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2012\/03\/26\/ppl-asynchronous-sample-pack-updated.aspx\">PPL Asynchronous Sample Pack<\/a> which includes a readymade implementation (<code>create_delayed_task<\/code>) in the <code>ppltasks_extra.h<\/code> header.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n#include &quot;ppltasks_extra.h&quot;\r\n\r\nusing namespace concurrency;\r\nusing namespace concurrency::extras;\r\n\/\/ ...\r\n\r\ntask&lt;int&gt; DelayForOneMillisecondAsync()\r\n{\r\n    return create_delayed_task(std::chrono::milliseconds(1), &#x5B;]()\r\n    {\r\n        return 42;\r\n    });\r\n}\r\n<\/pre>\n<p>To join on a group of tasks, PPL gives you <a href=\"\"><code>when_all<\/code><\/a> and <a href=\"\"><code>when_any<\/code><\/a> which are analogous to their <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.tasks.task.whenall(v=vs.110).aspx\">.NET<\/a> <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.tasks.task.whenany(v=vs.110).aspx\">namesakes<\/a> &#8212; with a C++ twist.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\nvector&lt;task&lt;void&gt;&gt; tasks;\r\ntasks.push_back(Do1Async());\r\ntasks.push_back(Do2Async());\r\n\r\n\/\/ Need to pass begin\/end iterators\r\nwhen_all(tasks.begin(), tasks.end()).get();\r\n<\/pre>\n<p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd984117.aspx\">Cooperative cancellation<\/a> is achieved with <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh749975.aspx\"><code>cancellation_token<\/code><\/a> and <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/hh749985.aspx\"><code>cancellation_token_source<\/code><\/a> which are, as expected, quite similar to their <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.cancellationtoken(v=vs.110).aspx\">.NET<\/a> <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.threading.cancellationtokensource(v=vs.110).aspx\">counterparts<\/a>.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\ncancellation_token_source cts;\r\ntask&lt;void&gt; task = LoopForeverAsync(cts.get_token());\r\n\r\nwcout &lt;&lt; L&quot;Press ENTER to cancel.&quot; &lt;&lt; endl;\r\nwstring line;\r\ngetline(wcin, line);\r\n\r\n\/\/ Request cancellation\r\ncts.cancel();\r\n\r\n\/\/ Task may complete with task_canceled exception\r\ntry\r\n{\r\n    task.get();\r\n}\r\ncatch (task_canceled const &amp;)\r\n{\r\n}\r\n<\/pre>\n<p>Perhaps the most surprising aspect to those accustomed to async in .NET is that the default <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd984036.aspx\">task scheduler<\/a> in the PPL <strong>does not support explicit synchronous continuations<\/strong>. Keep this in mind, especially when you are writing async unit tests &#8212; you may encounter unexpected thread switches.<\/p>\n<p>Overall, the PPL is a boon to C++ programmers who want to explore the wild world of async. In an upcoming post, I will show a more complete native async sample using the PPL.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Parallel Patterns Library (PPL) provides C++ developers with some very useful concurrency primitives along similar lines as Task parallelism in .NET. Having been introduced in Visual Studio 2010, the PPL is not new by any means. However, it remains&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[21,101],"tags":[],"class_list":["post-1901","post","type-post","status-publish","format-standard","hentry","category-async","category-native"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/1901","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1901"}],"version-history":[{"count":0,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/1901\/revisions"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1901"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1901"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1901"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}