<?xml version="1.0" encoding="UTF-8"?>

<!-- ====================================================================== -->
<!-- = chapter-6.xml                                                      = -->
<!-- = afnix programmer's guide chapter 6                                 = -->
<!-- ====================================================================== -->
<!-- = This  program  is  free  software; you  can redistribute it and/or = -->
<!-- = modify it provided that this copyright notice is kept intact.      = -->
<!-- = This program is distributed in the hope that it will be useful but = -->
<!-- = without  any  warranty;  without  even  the  implied  warranty  of = -->
<!-- = merchantability or fitness for  a  particular purpose. In no event = -->
<!-- = shall  the  copyright  holder be liable for any  direct, indirect, = -->
<!-- = incidental  or special  damages arising  in any way out of the use = -->
<!-- = of this software.                                                  = -->
<!-- ====================================================================== -->
<!-- = copyright (c) 2005-2007 - amaury darsch                            = -->
<!-- ====================================================================== -->

<chapter volume="1" number="6">
  <title>Threads operations</title>

  <p>
  This chapter covers the threads facilities builtin in the <afnix/>
  interpreter. The thread subsystem allows for the execution of
  concurrent   forms with an automatic synchronization
  mechanism. Designing a good   program with concurrent execution is a
  difficult task. It takes a   while to get used with the various
  synchronization mechanisms which   ensure a safe execution, that is
  no race condition or dead lock. Fortunately, <afnix/> provides some
  unique features that should ease such design.
  </p>

  <!-- normal and daemon threads -->
  <section>
    <title>Normal and daemon threads</title>

    <p>
    The interpreter supports two types of threads, called
    <em>normal and daemon threads</em>. A normal thread is started
    with the reserved keyword <code>launch</code>. A daemon thread is
    started with the reserved keyword <code>daemon</code>. The
    difference between a normal thread and a daemon thread is only in
    the termination of the interpreter. An <afnix/> program is
    completed when all normal threads have terminated. This means that
    the master thread (i.e the first thread) is suspended until all
    normal threads have been executed. With daemon threads, the master
    thread terminates even if some daemon threads are still running.
    </p>

    <!-- starting a normal thread -->
    <subsect>
      <title>Starting a normal thread</title>

      <p>
      A normal thread is started with the reserved keyword
      <code>launch</code>. The form to execute in a thread is the
      argument. The simplest thread to execute is the <code>nil</code>
      thread.
      </p>

      <example>
      launch (nil)
      </example>

      <p>
      Even the <code>nil</code> thread does nothing in term of
      computation, it does a lot of things internally by  turning on
      the shared objects subsystem.
      </p>
    </subsect>

    <!-- thread object and result -->
    <subsect>
      <title>Thread object and result</title>

      <p>
      When a thread terminate, the thread object holds the result of
      the last executed form. The thread object is returned by the
      <code>launch</code> or <code>daemon</code> command. The
      <code>thread-p</code> predicates returns <code>true</code> if
      the object is a thread descriptor. The thread type can be check
      with the <code>normal-p</code> or <code>daemon-p</code>
      predicates.
      </p>

      <example>
      const thr (launch (nil))
      println   (thread-p thr) # true
      println   (thr:normal-p) # true
      </example>

      <p>
      The member data <code>result</code> of the thread object holds
      the result of the thread. Although the result can be accessed at
      any time, the returned value will be nil until the thread as
      completed its execution.
      </p>

      <example>
      const thr (launch (nil))
      println   (thr:result)   # nilp
      </example>

      <p>
      Although the <afnix/> engine will ensure that the result is
      <code>nil</code> until the thread has completed its execution,
      it does not mean that it is a reliable approach to test until
      the result is not <code>nil</code>. The engine provides various
      mechanisms to synchronize a thread and eventually wait for its
      completion.
      </p>
    </subsect>
  </section>

  <!-- shared objects -->
  <section>
    <title>Shared objects</title>

    <p>
    The whole purpose of using a multi-threaded environment is to
    provide a concurrent execution with some shared variables. 
    Although, several threads can execute concurrently without sharing
    data, the most common situation is that one or more global
    variable are accessed -- and even changed -- by one or more
    threads. Various scenarios are possible. For example, a variable
    is changed by one thread, the other thread just read its
    value. Another scenario is one read, multiple write, or even more
    complicated, multiple read and multiple write. In any case, the
    interpreter subsystem must ensure that each objects are in a good
    state when such operation do occur.
    
    The <afnix/> engine provides an automatic synchronization
    mechanism for global objects, where only one thread can modify an
    object, but several thread can read it. This mechanism known as
    <em>read-write locking</em> guarantees that there is only one
    writer, but eventually multiple reader. When a thread start to
    modify an object, no other thread are allowed to read or write
    this object until the transaction has been completed. On the
    opposite, no thread is allowed to change (i.e. write) an object,
    until all thread which access (i.e. read)  the object value have
    completed the transaction. Because a context switch can occur at
    any time, the object read-write locking will ensure a safe
    protection during each concurrent access.

    Shared objects can be very complicated to detect. For example, if
    a vector is shared by various threads, the engine will make sure
    that all vector objects are also shared. A closed variable in a
    lambda or gamma expression is another example of potential shared
    object. Executing such lambda form in a thread will automatically
    mark the closed variables as shared objects. Additionally, when
    the thread system is started, all object in the global nameset are
    marked shared.
    </p>

    <!-- shared object predicate -->
    <subsect>
      <title>Shared object predicate</title>
      
      <p>
      The object predicate method <code>shared-p</code> returns true
      if an object is shared. Since all global objects are marked
      shared as soon as the thread system is turned on, the following
      example shows how a nil thread marks a shared variable.
      </p>

      <example>
      # create simple symbol
      const  a     1
      assert false (a:shared-p)

      # turn on the thread system
      launch (nil)
      assert true (a:shared-p)

      # check another symbol
      trans b 1
      assert true (b:shared-p)
      </example>

      <p>
      When an object is marked shared, it will remain in this state
      for rest of the session. Note that when an object is copied (by
      copy construction), the shared state is not copied. The copied
      object will become shared depending on its surrounding
      context. Such context can be a nameset or any other type of
      container which is shared or not. 
      </p>
    </subsect>

    <!-- shared protection access -->
    <subsect>
      <title>Shared protection access</title>

      <p>
      We illustrate the previous discussion with an interesting
      example and some variations around it. Let's consider a form
      which increase an integer object and another form which decrease
      the same integer object. If the integer is initialized to 0, and
      the two forms run in two separate threads, we might expect to
      see the value bounded by the time allocated for each thread. In
      other word, this simple example is a very good illustration of
      your machine scheduler.
      </p>

      <example>
      # shared variable access
      const var 0
      # increase method
      const incr nil (while true 
                 (println "increase: " (var:= (+ var 1))))
      # decrease method
      const decr nil (while true 
                 (println "decrease: " (var:= (- var 1))))

      # start both threads
      launch (decr)
      launch (incr)
      </example>

      <p>
      In the previous example, <code>var</code> is initialized to
      0. The <code>incr</code> thread increments <code>var</code>
      while the <code>decr</code> thread decrements
      <code>var</code>. Depending on the operating system, the result
      stays bounded within a certain range. The previous example can
      be changed by using the main thread or a third thread to print
      the variable value. The end result is the same, except that
      there is more threads competing for the shared variable.
      </p>

      <example>
      # shared variable access
      const var 0
 
      # incrementer, decrementer and printer
      const incr nil (while true (var:= (+ var 1)))
      const decr nil (while true (var:= (- var 1)))
      const prtv nil (while true (println "value = " var)

      # start all threads
      launch (decr)
      launch (incr)
      launch (prtv)
      </example>
    </subsect>
  </section>

  <!-- synchronization -->
  <section>
    <title>Synchronization</title>

    <p>
    Although, <afnix/> provides an automatic synchronization mechanism
    for reading or writing an object, it is sometimes necessary to
    control the execution flow. There are basically two techniques to
    do so. First, protect a form from being executed by several
    threads. Second, wait for one or several threads to complete their
    task before going to the next execution step.
    </p>

    <!-- form synchronization -->
    <subsect>
      <title>Form synchronization</title>

      <p>
      The reserved keyword <code>sync</code> can be used to
      synchronize a form. When a form, is synchronized, the <afnix/>
      engine guarantees that only one thread will execute this form.
      </p>

      <example>
      const print-message (code mesg) (
        sync {
	  errorln "error  : " code
	  errorln "message: " mesg
	}
      )
      </example>

      <p>
      The previous example create a gamma expression which make sure
      that both the error code and error message are printed in one
      group, when several threads call it.
      </p>
    </subsect>

    <!-- thread completion -->
    <subsect>
      <title>Thread completion</title>

      <p>
      The other piece of synchronization is the thread completion
      indicator. The thread descriptor contains a method called
      <code>wait</code> which suspend the calling thread until the
      thread attached to the descriptor has been completed. If the
      thread is already completed, the method returns immediately.
      </p>

      <example>
      # simple flag
      const flag false

      # simple shared tester
      const ftest (val) (flag) (assert val (flag:shared-p))

      # no thread mean not shared
      ftest false

      # in a thread it is shared
      const thr (launch (ftest true))
      thr:wait
      assert true (flag:shared-p)
      </example>

      <p>
      This example is taken from the test suites. It checks that a
      closed variable becomes shared when started in a thread. Note
      the use of the <code>wait</code> method to make sure the thread
      has completed before checking for the shared flag. It is also
      worth to note that <code>wait</code> is one of the method which
      guarantees that a thread result is valid.

      Another use of the <code>wait</code> method can be made with a
      vector of thread descriptors when one wants to wait until all of
      them have completed.
      </p>

      <example>
      # shared vector of threads descriptors
      const thr-group (Vector)

      # wait until all threads in the group are finished
      const wait-all nil (for (thr) (thr-group) (thr:wait))
      </example>
    </subsect>

    <!-- complete example -->
    <subsect>
      <title>Complete example</title>

      <p>
      We illustrate the previous discussion with a complete
      example. The idea is to perform a matrix multiplication. A
      thread is launched when when multiplying one line with one
      column. The result is stored in the thread descriptor. A vector
      of thread descriptor is used to store the result.
      </p>

      <example>
      # initialize the shared library
      interp:library "afnix-sys"

      # shared vector of threads descriptors
      const thr-group (Vector)

      # this procedure waits until all threads in 
      # the group are finished
      const wait-all nil (for (thr) (thr-group) (thr:wait))

      # this procedure initialize a matrix with random numbers
      # the matrix is a square one with its size as an argument
      const init-matrix (n) {
        trans i (Integer 0)
	const m (Vector)
	do {
	  trans v (m:append (Vector))
	  trans j (Integer)
	  do {
	    v:append (afnix:sys:get-random)
	  } (&lt; (j:++) n)
        } (&lt; (i:++) n)
        eval m
      }

      # this procedure multiply one line with one column
      const mult-line-column (u v) {
        assert (u:length) (v:length)
	trans result 0
	for (x y) (u v) (result:+= (* x y))
	eval result
      }

      # this procedure multiply two vectors assuming one 
      # is a line and one is a column coming from the matrix
      const mult-matrix (mx my) {
        for (lv) (mx) {
	  assert true (vector-p lv)
	  for (cv) (my) {
	    assert true (vector-p cv)
	    thr-group:append (launch (mult-line-column lv cv))
          }
        }
      }

      # check for some arguments
      # note the use of errorln method
      if (== 0 (interp:argv:length)) {
        errorln "usage: axi 0607.als size"
	afnix:sys:exit 1
      }

      # get the integer and multiply
      const n (Integer (interp:argv:get 0))
      mult-matrix (init-matrix n) (init-matrix n)

      # wait for all threads to complete
      wait-all

      # make sure we have the right number
      assert (* n n) (thr-group:length)
      </example>
    </subsect>

    <!-- condition variable -->
    <subsect>
      <title>Condition variable</title>

      <p>
      A <em>condition variable</em> is another mechanism to
      synchronize several threads. A condition variable is modeled
      with the <code>Condvar</code> object. At construction, the
      condition variable is initialized to <code>false</code>. A
      thread calling the <code>wait</code> method will block until the
      condition becomes <code>true</code>. The <code>mark</code>
      method can be used by a thread to change the state of a
      condition variable and eventually awake some threads which are
      blocked on it. The following example shows how the main thread
      blocks until another change the state of the condition.
      </p>

      <example>
      # create a condition variable
      const cv (Condvar)

      # this function runs in a thread - does some computation
      # and mark the condition variable
      const do-something nil {
        # do some computation
	....
	# mark the condition
	cv:mark
      }

      # start some computation in a thread
      launch (do-something)

      # block until the condition is changed
      cv:wait-unlock

      # continue here
      ...
      </example>

      <p>
      In this example, the condition variable is created at the
      beginning. The thread is started and the main thread blocks
      until the thread change the state of the condition variable. It
      is important to note the use of the <code>wait-unlock</code>
      method. When the main thread is re-started (after the condition
      variable has been marked), the main thread owns the lock
      associated with the condition variable. The
      <code>wait-unlock</code> method unlocks that lock when the main
      thread is restarted. Note also that the <code>wait-unlock</code>
      method reset the condition variable. if the <code>wait</code>
      method was used instead of <code>wait-unlock</code> the lock
      would still be owned by the main thread. Any attempt by other
      thread to call the mark method would result in the calling
      thread to block until the lock is released.

      The <code>Condvar</code> class has several methods which can be
      used to control the behavior of the condition variable. Most of
      them are related to lock control. The <code>reset</code> method
      reset the condition variable. The <code>lock</code> and
      <code>unlock</code> control the condition variable locking. The
      <code>mark</code>, <code>wait</code> and
      <code>wait-unlock</code> method controls the synchronization
      among several threads.
      </p>
    </subsect>
  </section>
</chapter>
