{"id":4769,"date":"2016-06-03T08:35:00","date_gmt":"2016-06-03T08:35:00","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/asynchronous-callable-wrappers\/"},"modified":"2023-06-26T12:55:48","modified_gmt":"2023-06-26T12:55:48","slug":"asynchronous-callable-wrappers","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/asynchronous-callable-wrappers\/","title":{"rendered":"Asynchronous Callable Wrappers"},"content":{"rendered":"<p><span style=\"font-family: courier new,courier;\">std::packaged_task<\/span> enables you to write a simple wrapper for a callable, which you can invoke later.<\/p>\n<p><!--more--><\/p>\n<h2>std::packaged_task<\/h2>\n<p>To deal with<span style=\"font-family: courier new,courier;\"> std::packaged_task,<\/span> you have to perform&nbsp;four steps usually:<\/p>\n<ol>\n<li>Wrap the task<\/li>\n<li>Create the future<\/li>\n<li>Perform the calculation<\/li>\n<li>Pick up the result<\/li>\n<\/ol>\n<p>These steps are easy to get with an example.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39\r\n40\r\n41\r\n42\r\n43\r\n44\r\n45\r\n46\r\n47\r\n48\r\n49\r\n50\r\n51\r\n52\r\n53\r\n54\r\n55\r\n56\r\n57\r\n58\r\n59\r\n60\r\n61\r\n62\r\n63\r\n64\r\n65\r\n66\r\n67<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ packagedTask.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;utility&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;future&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;deque&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">SumUp<\/span>{\r\n  public:\r\n    <span style=\"color: #2b91af;\">int<\/span> <span style=\"color: #0000ff;\">operator<\/span>()(<span style=\"color: #2b91af;\">int<\/span> beg, <span style=\"color: #2b91af;\">int<\/span> end){\r\n      <span style=\"color: #2b91af;\">long<\/span> <span style=\"color: #2b91af;\">long<\/span> <span style=\"color: #2b91af;\">int<\/span> sum{0};\r\n      <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #2b91af;\">int<\/span> i= beg; i &lt; end; ++i ) sum += i;\r\n      <span style=\"color: #0000ff;\">return<\/span> sum;\r\n    }\r\n};\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n  SumUp sumUp1;\r\n  SumUp sumUp2;\r\n  SumUp sumUp3;\r\n  SumUp sumUp4;\r\n\r\n  <span style=\"color: #008000;\">\/\/ define the tasks<\/span>\r\n  std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>(<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>)&gt; sumTask1(sumUp1);\r\n  std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>(<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>)&gt; sumTask2(sumUp2);\r\n  std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>(<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>)&gt; sumTask3(sumUp3);\r\n  std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>(<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>)&gt; sumTask4(sumUp4);\r\n\r\n  <span style=\"color: #008000;\">\/\/ get the futures<\/span>\r\n  std::future&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; sumResult1= sumTask1.get_future();\r\n  std::future&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; sumResult2= sumTask2.get_future();\r\n  std::future&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; sumResult3= sumTask3.get_future();\r\n  std::future&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; sumResult4= sumTask4.get_future();\r\n\r\n  <span style=\"color: #008000;\">\/\/ push the tasks on the container<\/span>\r\n  std::deque&lt; std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>(<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>)&gt; &gt; allTasks;\r\n  allTasks.push_back(std::move(sumTask1));\r\n  allTasks.push_back(std::move(sumTask2));\r\n  allTasks.push_back(std::move(sumTask3));\r\n  allTasks.push_back(std::move(sumTask4));\r\n  \r\n  <span style=\"color: #2b91af;\">int<\/span> begin{1};\r\n  <span style=\"color: #2b91af;\">int<\/span> increment{2500};\r\n  <span style=\"color: #2b91af;\">int<\/span> end= begin + increment;\r\n\r\n  <span style=\"color: #008000;\">\/\/ execute each task in a separate thread<\/span>\r\n  <span style=\"color: #0000ff;\">while<\/span> ( not allTasks.empty() ){\r\n    std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>(<span style=\"color: #2b91af;\">int<\/span>,<span style=\"color: #2b91af;\">int<\/span>)&gt; myTask= std::move(allTasks.front());\r\n    allTasks.pop_front();\r\n    std::<span style=\"color: #0000ff;\">thread<\/span> sumThread(std::move(myTask),begin,end);\r\n    begin= end;\r\n    end += increment;\r\n    sumThread.detach();\r\n  }\r\n\r\n  <span style=\"color: #008000;\">\/\/ get the results<\/span>\r\n  <span style=\"color: #0000ff;\">auto<\/span> sum= sumResult1.get() + sumResult2.get() + sumResult3.get() + sumResult4.get();\r\n\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"sum of 0 .. 10000 = \"<\/span> &lt;&lt; sum &lt;&lt; std::endl;\r\n\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The job of the program is not so heavy. Calculate the sum from 0 to 10000 with the help of four threads and sum up the results with the associated futures. Of course, you can use the&nbsp;<a href=\"https:\/\/de.wikipedia.org\/wiki\/Gau%C3%9Fsche_Summenformel\">Gau\u00dfschen Summenformel<\/a>. (Strange, there is no English page describing this famous algorithm. But math is international.).<\/p>\n<p>I pack the work packages in std::packaged_task (lines 28 &#8211; 31) objects in the first step. Work packages are instances of the class<span style=\"font-family: courier new,courier;\"> SumUp<\/span> (lines 9 &#8211; 16). The call operator does the current work (lines 11-15). The call operator sums up all numbers from <span style=\"font-family: courier new,courier;\">beg<\/span> to <span style=\"font-family: courier new,courier;\">end<\/span> and returns the <span style=\"font-family: courier new,courier;\">sum<\/span>. std::packaged_task in lines 28 &#8211; 31 can deal with callables that need two ints and return an int.<\/p>\n<p>Now, I have to create in the <strong>second step<\/strong> the future objects with the help of <span style=\"font-family: courier new,courier;\">std::packaged_task<\/span> objects. Precisely that is done in lines 34 to 37. The packaged_task is the promise in the <a href=\"https:\/\/www.modernescpp.com\/index.php\/tasks\">communication channel<\/a>. In these lines, I define the type of the future: <span style=\"font-family: courier new,courier;\">std::future&lt;int&gt; sumResult1= sumTask1.get_future(<\/span>), but of course, I can do it also&nbsp;implicitly: <span style=\"font-family: courier new,courier;\">auto sumResult1= sumTask1.get_future()<\/span>.<\/p>\n<p>In the <strong>third step<\/strong>, the work takes place. The packaged_task is moved onto the <span style=\"font-family: courier new,courier;\">std::deque<\/span> (lines 40 &#8211; 44). Each packaged_task (lines 51 &#8211; 58) is executed in the while loop. To do that, I move the head of the <span style=\"font-family: courier new,courier;\">std::deque<\/span> in a <span style=\"font-family: courier new,courier;\">std::packaged_task<\/span> (line 52), move the packaged_task in a new thread (line 54) and let it run in the background (line 56). <span style=\"font-family: courier new,courier;\">std::packaged_task<\/span> object is not copyable. That&#8217;s why I used move semantic in lines 52 and 54. This restriction holds for all promises but also futures and threads. There is one exception to this rule: std:.shared_future.<\/p>\n<p>In the <strong>fourth and last step<\/strong>, the four futures ask with the get call for the results and sum them up (line 61).<\/p>\n<\/p>\n<p>Honestly, <span style=\"font-family: courier new,courier;\">std::packaged_task<\/span> was not made for a simple use case like<span style=\"font-family: courier new,courier;\"> std::async<\/span>. But the result is simple.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4768\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/packagedTask.png\" alt=\"packagedTask\" width=\"647\" height=\"181\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/packagedTask.png 647w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/06\/packagedTask-300x84.png 300w\" sizes=\"auto, (max-width: 647px) 100vw, 647px\" \/><\/p>\n<h3>Optimization potential<\/h3>\n<p>C++11 has a function <span style=\"font-family: courier new,courier;\">std::thread_hardware_concurrency<\/span>. It provides a hint about the number of cores on your system. If the C++ runtime has no glue, it conforms to the standard to return 0. So you should verify that value in your program (line 31). With the current GCC, Clang, or Microsoft compiler, I get the right answer 4. I use this number of cores In the variation of the program<span style=\"font-family: courier new,courier;\"> packagedTask.cpp<\/span>, to adjust the software to my hardware. So, my hardware is fully utilized.<\/p>\n<p><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39\r\n40\r\n41\r\n42\r\n43\r\n44\r\n45\r\n46\r\n47\r\n48\r\n49\r\n50\r\n51\r\n52\r\n53\r\n54\r\n55\r\n56\r\n57\r\n58\r\n59\r\n60\r\n61\r\n62\r\n63\r\n64\r\n65\r\n66\r\n67\r\n68\r\n69\r\n70\r\n71\r\n72<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ packagedTaskHardwareConcurrency.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;algorithm&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;future&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;deque&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">class<\/span> <span style=\"color: #2b91af;\">SumUp<\/span>{\r\npublic:\r\n  SumUp(<span style=\"color: #2b91af;\">int<\/span> b, <span style=\"color: #2b91af;\">int<\/span> e): beg(b),end(e){}\r\n  <span style=\"color: #2b91af;\">int<\/span> <span style=\"color: #0000ff;\">operator<\/span>()(){\r\n    <span style=\"color: #2b91af;\">long<\/span> <span style=\"color: #2b91af;\">long<\/span> <span style=\"color: #2b91af;\">int<\/span> sum{0};\r\n    <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #2b91af;\">int<\/span> i= beg; i &lt; end; ++i ) sum += i;\r\n    <span style=\"color: #0000ff;\">return<\/span> sum;\r\n  }\r\nprivate:\r\n    <span style=\"color: #2b91af;\">int<\/span> beg;\r\n    <span style=\"color: #2b91af;\">int<\/span> end;\r\n};\r\n\r\n<span style=\"color: #0000ff;\">static<\/span> <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> hwGuess= 4;\r\n<span style=\"color: #0000ff;\">static<\/span> <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> numbers= 10001;\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n  <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> hw= std::<span style=\"color: #0000ff;\">thread<\/span>::hardware_concurrency();\r\n  <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> hwConcurr= (hw != 0)? hw : hwGuess;\r\n\r\n  <span style=\"color: #008000;\">\/\/ define the functors<\/span>\r\n  std::vector&lt;SumUp&gt; sumUp;\r\n  <span style=\"color: #0000ff;\">for<\/span> ( <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> i= 0; i &lt; hwConcurr; ++i){\r\n    <span style=\"color: #2b91af;\">int<\/span> begin= (i*numbers)\/hwConcurr;\r\n    <span style=\"color: #2b91af;\">int<\/span> end= (i+1)*numbers\/hwConcurr;\r\n    sumUp.push_back(SumUp(begin ,end));\r\n  }\r\n\r\n  <span style=\"color: #008000;\">\/\/ define the tasks<\/span>\r\n  std::deque&lt;std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>()&gt;&gt; sumTask;\r\n  <span style=\"color: #0000ff;\">for<\/span> ( <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> i= 0; i &lt; hwConcurr; ++i){\r\n    std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>()&gt; SumTask(sumUp[i]);\r\n    sumTask.push_back(std::move(SumTask));\r\n  }\r\n\r\n  <span style=\"color: #008000;\">\/\/ get the futures<\/span>\r\n  std::vector&lt; std::future&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;&gt; sumResult;\r\n  <span style=\"color: #0000ff;\">for<\/span> ( <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> i= 0; i &lt; hwConcurr; ++i){\r\n    sumResult.push_back(sumTask[i].get_future());\r\n  }\r\n\r\n  <span style=\"color: #008000;\">\/\/ execute each task in a separate thread<\/span>\r\n  <span style=\"color: #0000ff;\">while<\/span> ( not sumTask.empty() ){\r\n    std::packaged_task&lt;<span style=\"color: #2b91af;\">int<\/span>()&gt; myTask= std::move(sumTask.front());\r\n    sumTask.pop_front();\r\n    std::<span style=\"color: #0000ff;\">thread<\/span> sumThread(std::move(myTask));\r\n    sumThread.detach();\r\n  }\r\n\r\n  <span style=\"color: #008000;\">\/\/ get the results<\/span>\r\n  <span style=\"color: #2b91af;\">int<\/span> sum= 0;\r\n  <span style=\"color: #0000ff;\">for<\/span> ( <span style=\"color: #2b91af;\">unsigned<\/span> <span style=\"color: #2b91af;\">int<\/span> i= 0; i &lt; hwConcurr; ++i){\r\n    sum += sumResult[i].get();\r\n  }\r\n\r\n  std::cout &lt;&lt; <span style=\"color: #a31515;\">\"sum of 0 .. 100000 = \"<\/span> &lt;&lt; sum &lt;&lt; std::endl;\r\n\r\n  std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>The <a href=\"https:\/\/www.modernescpp.com\/index.php\/promise-and-future\">next post <\/a>will be about futures and promises. (<strong>Proofreader Alexey Elymanov<\/strong>)<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>std::packaged_task enables you to write a simple wrapper for a callable, which you can invoke later.<\/p>\n","protected":false},"author":21,"featured_media":4768,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[366],"tags":[446],"class_list":["post-4769","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-multithreading","tag-tasks"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4769","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=4769"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4769\/revisions"}],"predecessor-version":[{"id":6976,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/4769\/revisions\/6976"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/4768"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=4769"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=4769"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=4769"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}