Skip to content

Commit 56ee56a

Browse files
committed
more documentation on tasks. ref #4857
1 parent 2126e18 commit 56ee56a

File tree

1 file changed

+60
-3
lines changed

1 file changed

+60
-3
lines changed

doc/manual/control-flow.rst

+60-3
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,63 @@ directly or by use of a convenience macro::
769769
# or, equivalently
770770
taskHdl = @task mytask(7)
771771

772-
``produce`` and ``consume`` are intended for multitasking, and do not
773-
launch threads that can run on separate CPUs. True kernel threads are
774-
discussed under the topic of :ref:`man-parallel-computing`.
772+
``produce`` and ``consume`` do not launch threads that can run on separate CPUs.
773+
True kernel threads are discussed under the topic of :ref:`man-parallel-computing`.
774+
775+
Core task operations
776+
~~~~~~~~~~~~~~~~~~~~
777+
778+
While ``produce`` and ``consume`` illustrate the essential nature of tasks, they
779+
are actually implemented as library functions using a more primitive function,
780+
``yieldto``. ``yieldto(task,value)`` suspends the current task, switches
781+
to the specified ``task``, and causes that task's last ``yieldto`` call to return
782+
the specified ``value``. Notice that ``yieldto`` is the only operation required
783+
to use task-style control flow; instead of calling and returning we are always
784+
just switching to a different task. This is why this feature is also called
785+
"symmetric coroutines"; each task is switched to and from using the same mechanism.
786+
787+
``yieldto`` is powerful, but most uses of tasks do not invoke it directly.
788+
Consider why this might be. If you switch away from the current task, you will
789+
probably want to switch back to it at some point, but knowing when to switch
790+
back, and knowing which task has the responsibility of switching back, can
791+
require considerable coordination. For example, ``produce`` needs to maintain
792+
some state to remember who the consumer is. Not needing to manually keep track
793+
of the consuming task is what makes ``produce`` easier to use than ``yieldto``.
794+
795+
In addition to ``yieldto``, a few other basic functions are needed to use tasks
796+
effectively.
797+
``current_task()`` gets a reference to the currently-running task.
798+
``istaskdone(t)`` queries whether a task has exited.
799+
``istaskstarted(t)`` queries whether a task has run yet.
800+
``task_local_storage`` manipulates a key-value store specific to the current task.
801+
802+
Tasks and events
803+
~~~~~~~~~~~~~~~~
804+
805+
Most task switches occur as a result of waiting for events such as I/O
806+
requests, and are performed by a scheduler included in the standard library.
807+
The scheduler maintains a queue of runnable tasks, and executes an event loop
808+
that restarts tasks based on external events such as message arrival.
809+
810+
The basic function for waiting for an event is ``wait``. Several objects
811+
implement ``wait``; for example, given a ``Process`` object, ``wait`` will
812+
wait for it to exit. ``wait`` is often implicit; for example, a ``wait``
813+
can happen inside a call to ``read`` to wait for data to be available.
814+
815+
In all of these cases, ``wait`` ultimately operates on a ``Condition``
816+
object, which is in charge of queueing and restarting tasks. When a task
817+
calls ``wait`` on a ``Condition``, the task is marked as non-runnable, added
818+
to the condition's queue, and switches to the scheduler. The scheduler will
819+
then pick another task to run, or block waiting for external events.
820+
If all goes well, eventually an event handler will call ``notify`` on the
821+
condition, which causes tasks waiting for that condition to become runnable
822+
again.
823+
824+
A task created explicitly by calling ``Task`` is initially not known to the
825+
scheduler. This allows you to manage tasks manually using ``yieldto`` if
826+
you wish. However, when such a task waits for an event, it still gets restarted
827+
automatically when the event happens, as you would expect. It is also
828+
possible to make the scheduler run a task whenever it can, without necessarily
829+
waiting for any events. This is done by calling ``schedule(task)``, or using
830+
the ``@schedule`` or ``@async`` macros (see :ref:`man-parallel-computing` for
831+
more details).

0 commit comments

Comments
 (0)