.. default-domain:: chpl .. _primers-syncs: Sync ==== `View syncs.chpl on GitHub `_ This primer illustrates Chapel's sync variables. ``sync`` is a type qualifier that can be applied to the Chapel primitive types ``nothing``, ``bool``, ``int``, ``uint``, ``real``, ``imag``, ``complex``, ``range``, ``bytes``, and ``string``; to enumerated types; and to class types and record types. Sync variables have an associated state that is either ``full`` or ``empty``. If a sync variable is declared with an initializing expression, its state is set to ``full`` and its value is that of the expression. Without an initializing expression, a sync variable's state is set to ``empty`` and its value is the default value for the base type. .. code-block:: chapel config const n = 7; var si: sync int=1; // state = full, value = 1 var sb: sync bool; // state = empty, value = false Because of their full/empty state, reads and writes to sync variables must be done with methods to make it clear how the full/empty state is treated in the operation. If a sync variable is not in the correct state for a given operation, the current task blocks until it is. Here are the methods defined on sync variables: The ``writeEF()`` method blocks until the state is ``empty`` and then assigns the value argument to the variable and then sets the state to ``full``. .. code-block:: chapel sb.writeEF(true); The ``readFE()`` method blocks until the state is ``full`` and then reads the value of the variable, sets the state to ``empty``, and then returns the value. .. code-block:: chapel var si2 = si.readFE(); writeln("si2 ", si2); The ``readFF()`` method blocks until the state is ``full`` and then reads the value of the variable and returns the value. The state remains ``full``. .. code-block:: chapel var sb2 = sb.readFF(); writeln("sb2 ", sb2); The following creates a new task via a :ref:`begin ` statement and declares a variable ``si4`` that is initialized using ``si``. The initialization statement will block until ``si`` is ``full``. The last statement in the ``begin`` block sets ``done`` to ``full``. .. code-block:: chapel var done: sync bool; writeln("Launching new task"); begin { var si4 = si.readFE(); // This statement will block until si is full writeln("New task unblocked, si4=", si4); done.writeEF(true); } Recall that execution proceeds immediately following the ``begin`` statement after task creation. .. code-block:: chapel writeln("After launching new task"); When ``si`` is written, its state will be set to ``full`` and the blocked task above will continue. .. code-block:: chapel si.writeEF(n); This next statement blocks until the last statement in the above ``begin`` completes. .. code-block:: chapel done.readFE(); Example: simple split-phase barrier for tasks .. code-block:: chapel var count: sync int = n; // counter which also serves as a lock var release: sync bool; // barrier release coforall t in 1..n { var myc = count.readFE(); // read the count, grab the lock (state = empty) if myc!=1 { // still waiting for others write("."); count.writeEF(myc-1); // update the count, release the lock (state = full) // we could do some work while waiting release.readFF(); // wait for everyone } else { // last one here release.writeEF(true); // release everyone first (state = full) writeln("done"); } } Sync arguments are passed by reference. As a result, the state of the variable does not change. .. code-block:: chapel si.writeEF(4*n); writeln("now passing to f_withSyncIntFormal"); f_withSyncIntFormal(si); When passing a sync variable to a generic formal, whether with a ``ref`` intent or a default intent, the variable is passed by reference. The state of the variable does not change and sync operations are available. .. code-block:: chapel f_withGenericDefaultIntentFormal(si); f_withGenericDefaultIntentFormal(sb); f_withGenericRefFormal(si); f_withGenericRefFormal(sb); Currently, sync variables cannot be written out directly. We need to extract the value, for example using ``readFE()`` or ``readFF()``. .. code-block:: chapel writeln(si.readFF()); writeln(si.readFE()); Definitions of functions used above .. code-block:: chapel proc f_withSyncIntFormal(x: sync int) { writeln("the value is: ", x.readFF()); } proc f_withGenericDefaultIntentFormal(x) { writeln("the value is: ", x.readFF()); } proc f_withGenericRefFormal(ref x) { writeln("the value is: ", x.readFF()); }