<ahref="#AsyncProducerConsumerIsDone">Conditional Consumption with Cooperative Execution</a>
</li>
</ul>
</div>
<divclass="textblock"><p>We implement a producer-consumer pipeline using dependent-async tasks, demonstrating how <aclass="el" href="classtf_1_1Executor.html#a0015352aa28b50251a970354a0c4a159" title="runs the given function asynchronously when the given predecessors finish">tf::Executor::dependent_async</a> naturally expresses stage-level dependencies between data items and how production and consumption overlap in time without any manual synchronization.</p>
<p>A producer generates <code>N</code> data items one by one. Each item must pass through a validator before it can be consumed. Consumption can begin as soon as an item is validated. There is no need to wait for the entire input to be produced first. The three-stage pipeline per item is:</p>
<oltype="1">
<li><b>Produce:</b> generate the data item</li>
<li><b>Validate:</b> verify the item is correct</li>
<li><b>Consume:</b> process the validated item</li>
</ol>
<p>Items are independent of each other across all three stages, so stages of different items can overlap in time. This is exactly the kind of dynamic, data-driven structure that <aclass="el" href="classtf_1_1Executor.html#a0015352aa28b50251a970354a0c4a159" title="runs the given function asynchronously when the given predecessors finish">tf::Executor::dependent_async</a> is designed for.</p>
<p>The following diagram illustrates the overlapping execution of four items through the three stages. Each item's stages are wired by dependency edges so that Produce must finish before Validate, and Validate before Consume. Because items are independent of one another, the executor schedules stages of different items in parallel whenever workers are available:</p>
<p>We create three dependent-async tasks per item. Each task depends on the previous stage of the <em>same</em> item. Because <aclass="el" href="classtf_1_1Executor.html#a0015352aa28b50251a970354a0c4a159" title="runs the given function asynchronously when the given predecessors finish">tf::Executor::dependent_async</a> begins executing a task as soon as all its predecessors complete, item <code>i+1</code> can be produced while item <code>i</code> is being validated and item <code>i-1</code> is being consumed:</p>
<divclass="ttc" id="aclasstf_1_1Executor_html_a09e04696a50841c118472b2c2a7ff6f5"><divclass="ttname"><ahref="classtf_1_1Executor.html#a09e04696a50841c118472b2c2a7ff6f5">tf::Executor::silent_dependent_async</a></div><divclass="ttdeci">tf::AsyncTask silent_dependent_async(F &&func, Tasks &&... tasks)</div><divclass="ttdoc">runs the given function asynchronously when the given predecessors finish</div></div>
<divclass="ttc" id="aclasstf_1_1Executor_html_ab9aa252f70e9a40020a1e5a89d485b85"><divclass="ttname"><ahref="classtf_1_1Executor.html#ab9aa252f70e9a40020a1e5a89d485b85">tf::Executor::wait_for_all</a></div><divclass="ttdeci">void wait_for_all()</div><divclass="ttdoc">waits for all tasks to complete</div></div>
</div><!-- fragment --><p>Because each stage only depends on the previous stage of the <em>same</em> item rather than on the previous item's stages, the executor's work-stealing scheduler can run all three stages of different items concurrently across available workers. No mutex, condition variable, or queue is needed; the dependency edges express all synchronization requirements.</p>
Conditional Consumption with Cooperative Execution</h1>
<p>In some pipelines, the main thread needs to inspect intermediate results before deciding what to submit next. <aclass="el" href="classtf_1_1AsyncTask.html#aefeefa30d7cafdfbb7dc8def542e8e51" title="checks if this dependent-async task finishes">tf::AsyncTask::is_done</a> provides a non-blocking way to check whether a specific task has completed. Combined with <aclass="el" href="classtf_1_1Executor.html#a0fc6eb19f168dc4a9cd0a7c6187c1d2d" title="keeps running the work-stealing loop until the predicate returns true">tf::Executor::corun_until</a>, the calling thread remains active in the work-stealing loop while polling and never blocks.</p>
<p>The example below produces and validates one item, polls completion, and conditionally submits a downstream task based on the validation result:</p>
<divclass="ttc" id="aclasstf_1_1AsyncTask_html_aefeefa30d7cafdfbb7dc8def542e8e51"><divclass="ttname"><ahref="classtf_1_1AsyncTask.html#aefeefa30d7cafdfbb7dc8def542e8e51">tf::AsyncTask::is_done</a></div><divclass="ttdeci">bool is_done() const</div><divclass="ttdoc">checks if this dependent-async task finishes</div><divclass="ttdef"><b>Definition</b> async_task.hpp:292</div></div>
<divclass="ttc" id="aclasstf_1_1Executor_html"><divclass="ttname"><ahref="classtf_1_1Executor.html">tf::Executor</a></div><divclass="ttdoc">class to create an executor</div><divclass="ttdef"><b>Definition</b> executor.hpp:62</div></div>
<divclass="ttc" id="aclasstf_1_1Executor_html_a0015352aa28b50251a970354a0c4a159"><divclass="ttname"><ahref="classtf_1_1Executor.html#a0015352aa28b50251a970354a0c4a159">tf::Executor::dependent_async</a></div><divclass="ttdeci">auto dependent_async(F &&func, Tasks &&... tasks)</div><divclass="ttdoc">runs the given function asynchronously when the given predecessors finish</div></div>
<divclass="ttc" id="aclasstf_1_1Executor_html_a0fc6eb19f168dc4a9cd0a7c6187c1d2d"><divclass="ttname"><ahref="classtf_1_1Executor.html#a0fc6eb19f168dc4a9cd0a7c6187c1d2d">tf::Executor::corun_until</a></div><divclass="ttdeci">void corun_until(P &&predicate)</div><divclass="ttdoc">keeps running the work-stealing loop until the predicate returns true</div></div>
</div><!-- fragment --><dlclass="section note"><dt>Note</dt><dd><aclass="el" href="classtf_1_1AsyncTask.html#aefeefa30d7cafdfbb7dc8def542e8e51" title="checks if this dependent-async task finishes">tf::AsyncTask::is_done</a> is designed to be used with <aclass="el" href="classtf_1_1Executor.html#a0fc6eb19f168dc4a9cd0a7c6187c1d2d" title="keeps running the work-stealing loop until the predicate returns true">tf::Executor::corun_until</a>. Calling <code>is_done</code> in a tight spin-wait without <code>corun_until</code> risks starving the worker thread pool if the calling thread is itself one of the executor's workers. See <aclass="el" href="DependentAsyncTasking.html">Asynchronous Tasking with Dependencies</a> for a full discussion of the dependent-async API. </dd></dl>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.13.1-->
<!-- start footer part -->
<divid="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<liclass="navelem"><aclass="el" href="Examples.html">Learning from Examples</a></li>
<liclass="footer">
Maintained by <ahref="https://tsung-wei-huang.github.io/">Dr. Tsung-Wei Huang</a>
—
Generated by <ahref="https://www.doxygen.org/index.html"><imgclass="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.13.1