[NAME]
ALL.dao.tutorial.concurrent

[TITLE]
Concurrent Programming

[DESCRIPTION]

Dao has several features that support concurrent programming. The first is a concurrent
Garbage Collector (GC), which works behind the scene. The other features come in the
following forms: multi-threading module, asynchronous function call and asynchronous
object, which are built around a lightweight thread pool with a simple scheduler to map
thread tasks (or tasklets) to native threads.

 0.1   Multi-threading Module  

The Multi-threading Module ( mt) offers the traditional multi-threading based on threads
with mutexes, condition variables and semaphores. The main functionalities of mt are 
provided as code section methods for maximum flexibility and expressiveness. For example,
a tasklet can be started with the mt.start() method, 
     
   1  fut1 = mt.start {
   2      sum = 0;
   3      for( i = 1 : 10000 ) sum += i * i
   4      return sum
   5  }
   6  fut2 = mt.start( $now ) {
   7      sum = 0;
   8      for( i = 1 : 10000 ) sum += i * i
   9      return sum
  10  }
  11  io.writeln( fut1.value(), fut2.value() )
     
mt.start() can execute any expression or block of codes as a tasklet, which may be 
scheduled to run when a native thread become available to it. If the tasklet needs to be
started immediately, the additional parameter $now can be passed to mt.start(), so that 
a new native thread may be created if there is no other native thread available for the
task.

mt.start() returns a future value which will be used to store the value returned by the 
tasklet. Accessing its value by future.value() will cause the current tasklet to block 
until the value becomes available after the tasklet finishs. If one wants to wait for the
task for only a limited amount of time, the method future.value() can be used with a 
timeout parameter (a float value for seconds or fraction seconds, negative for infinite
waiting).

 0.2   Parallelized Code Section Methods  

However, the simplest way to do threaded programming is to use the following parallelized
code section methods of mt, 
  *  iterate():
     Iterate a predefined number of times, or iterate over a list, map or array, and
     execute the code block on each of the items;
  *  map()
     Map a list, map or array to another list, map or array, using the values returned by
     the code block;
  *  apply()
     Apply the values returned by the code block to a list, map or array;
  *  find()
     Find the first item in a list or map the satisfy the condition as tested by the code
     block.


The default number of threads used by these methods are 2. Examples,
     
   1  ls = {1,2,3,4,5,6}
   2  
   3  # Use 2 threads to iterate 10 times:
   4  mt.iterate( 10 ) { io.writeln( X ) }
   5  
   6  # Use 3 threads to iterate over a list:
   7  mt.iterate( ls, 3 ) { io.writeln( X ) }
   8  
   9  mt.map( ls, 2 ) { X*X } # produces new list: {1,4,9,16,25,36}
  10  mt.apply( ls, 2 ) { X*X } # ls becomes: {1,4,9,16,25,36}
     


 0.3   Asynchronous Function Call  

Asynchronous Function Call (AFC) allows a function call to be executed as a tasklet, and
return immediately a future value that can be use to block on the tasklet and wait for
its completion.

Any standard function call followed by !! will start an AFC. 
     
   1  routine MyFunction( n = 10 )
   2  {
   3      for( i = 1 : n ) io.writeln( i )
   4  }
   5  f = MyFunction( 20 ) !!
   6  io.writeln( f.value() )
     


When multiple methods of a class instance are called in asynchronous mode, their
execution will be mutually exclusive, namely, at any given time only call (tasklet) can
be active. So in this way, the class instance acts just like a monitor.

 0.4   Asynchronous Object  


An asynchronous object is a class instance that is created with asynchronous call mode,
     
   1  async_objet = some_class( ... ) !!
     

When an asynchronous object invokes a method, it will be automatically called in
asynchronous mode, and start a tasklet and return a future value. Such tasklets are
queued and and executed in the order they are queued.

So such asynchronous object acts like an actor in the actor model considering that 
calling methods of such object is just like sending messages to the object with function
parameters being the message contents. For each instance, these messages are processed
one by one in the order of receiving.

Here is an simple example,
     
   1  class Account
   2  {
   3      private
   4  
   5      var balance = 0
   6  
   7      public
   8  
   9      routine Account( init = 0 ){
  10          balance = init
  11      }
  12      routine Withdraw( amount : int ) => enum<false,true>
  13      {
  14          if ( balance < amount ) return $false
  15          balance -= amount
  16          return $true
  17      }
  18      routine Deposit( amount : int ) => int
  19      {
  20          balance += amount
  21          return balance
  22      }
  23      routine Balance() => int
  24      {
  25          return balance
  26      }
  27  }
  28  
  29  acount1 = Account( 100 ) !!
  30  acount2 = Account( 100 ) !!
  31  
  32  future1 = acount1.Withdraw( 10 )
  33  if( future1.value() == $true ) future2 = acount2.Deposit( 10 )
  34  
  35  future3 = acount1.Deposit( 20 )
  36  
  37  io.writeln( 'Balance in account1:', acount1.Balance().value() )
  38  io.writeln( 'Balance in account2:', acount2.Balance().value() )
     

Like calling mt.start(), calling a method on an asynchronous object will return a future
value, which can be used to check the status of the asynchronous call.

 0.5   Communication Channels  

Tasklets (represented by future values) created from mt::start, asynchronous function 
call and the methods of asynchronous object can be assigned to native threads to run
concurrently. Tasklets can communicate and synchronize with each other using 
communication channels.

The channel type is implemented as a customized C data type that supports template-like 
type arguments. So to construct a channel that can send and receive integers, one can
use,
     
   1  chan = mt::channel<int>()
     
Here channel is prefixed with mt::, because channel is defined in the built-in mt 
multi-threading module.

The type argument int indicates this channel can only be used to transmit integers. 
Currently, only primitive types ( int, float, double, complex, string, enum) plus array 
types, and their composition through list, map and tuple types are supported for 
channels.

Each channel has a capacity for transmitting data, which are buffered in the channel.
When the channel's buffer reached its capacity, any attempt to send data to it will
result in the blocking of the sender, which will be resumed either after a timeout or
after some data of the channel have been read out of the buffer to make room for the new
data being sent by the blocked sender. Channel capacity can be passed to the constructor 
of the channel as an optional parameter, which is one by default.

The essential methods of channel are:
  *  send(): for sending data to the channel;
  *  receive(): for receiving data from the channel;
  *  select(): for selecting a group of channels;
See dao.concurrent.channel for details. Here is a simple example, 
     
   1  chan = mt::channel<int>(2)
   2  
   3  produce = mt.start {
   4      index = 0;
   5      while( ++index <= 10 ){
   6          io.writeln( 'sending', index )
   7          chan.send( index )
   8      }
   9      chan.cap(0)  # set channel buffer size to zero to close the channel;
  10  }
  11  
  12  consume = mt.start {
  13      while(1){
  14          data = chan.receive()
  15          io.writeln( "received", data );
  16          if( data.status == $finished ) break
  17      }
  18  }