@@ -769,6 +769,63 @@ directly or by use of a convenience macro::
769
769
# or, equivalently
770
770
taskHdl = @task mytask(7)
771
771
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