Work Items / tmc::post()
=========================================

.. toctree::
   :maxdepth: 2
   :hidden:

   post
   post_bulk
   post_waitable
   post_bulk_waitable


Work Item Types
-----------------------------------

A work item is any type that can be submitted for execution to a TMC executor.

The first-class work item type of TMC is the coroutine :literal_ref:`tmc::task<task>`.
However, the TMC executors / utility functions offer support for a variety of other work item types.
Generally, any type that implements ``operator()()`` can be submitted to any of TMC's executors.
This includes functors, tasks, and external coroutines.

.. _work_item_functor:

Functors as Work Items
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Any object that exposes ``operator()()`` is a Functor. This includes:

* std::function<Result()> / std::function<void()>
* lambda functions (value or void-returning)
* functors (value or void-returning)
* free functions (value or void-returning)

* :ref:`external (non-TMC) coroutines<work_item_coroutine>`


:literal_ref:`tmc::task<task>` as a Work Item
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ``post()`` family of functions have overloads that detect when a :literal_ref:`tmc::task<task>` is passed
and allow you to synchronously wait for the task to complete and/or retrieve a result, as if it were awaited.

(tasks are technically functors, but this special handling allows them to be "awaited" in a sync context)

.. _work_item_coroutine:

External Coroutines as Work Items
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unlike ``tmc::task``, external coroutine types aren't handled specially by the ``post`` functions.
They will be treated as if they were any other void-returning functor.

They will only be resumed 1 time (by calling ``operator()()``) after which ``post_waitable()`` will return.
If they return a result, it cannot be retrieved, and storage for it may not be properly available, depending on the coroutine implementation.

Because of this, you can safely use them with :literal_ref:`tmc::post()<post>` / :literal_ref:`tmc::post_bulk()<post_bulk>`, but don't try to wait for them
to finish with the ``waitable()`` variants - it won't behave as expected.

External coroutines are often awaitables, and would behave as expected when ``co_await`` ed or with the ``tmc::spawn()`` family of functions.
Therefore it is generally recommended to await external coroutines from within a :literal_ref:`tmc::task<task>`, in order to ensure that they complete successfully.

post() functions: the sync-to-async bridge
------------------------------------------------

``tmc::task<void>`` and void-returning functors may be submitted directly to an executor with:

* :literal_ref:`tmc::post()<post>` to submit a single work item
* :literal_ref:`tmc::post_bulk()<post_bulk>` to submit multiple work items
* :literal_ref:`tmc::post_waitable()<post_waitable>` to submit a single work item and wait (block) until the result is ready
* :literal_ref:`tmc::post_bulk_waitable()<post_bulk_waitable>` to submit multiple work items and wait (block) until they finish

``tmc::task<Result>`` and Result-returning functors may only be submitted with:

* :literal_ref:`tmc::post_waitable()<post_waitable>` to submit a single work item and wait (block) until the result is ready

The quickstart function ``tmc::async_main()`` is provided to easily enter the TMC execution context at the beginning of the program.
If your application is coroutine-based, it is recommended to call this function first, and then use :literal_ref:`tmc::spawn()<spawn>` to
create additional work instead of using the ``tmc::post()`` family of functions.

