[NAME]
ALL.dao.concurrent.channel

[TITLE]
Communication Channel

[DESCRIPTION]

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 channel type has a number of methods which include:
  *  buffer( self :channel<@V> ) => int
     It returns the number of unprocessed data items in the channel buffer.
  *  cap( self :channel<@V> ) => int
     Return the channel capacity.
  *  cap( self :channel<@V>, cap :int ) => int
     Set the channel capacity and returns the previous one. Set the capacity to zero to
     prevent it from receiving further data, and effectively close it when its buffer
     become empty.
  *  send( self :channel<@V>, data :@V, timeout :float = -1 ) => int
     Send a data item with a timeout. A negative timeout parameter means infinite
     waiting. It return 1 upon timeout, 0 otherwise.
  *  receive( self :channel<@V>, timeout :float = -1 ) => tuple<data :@V|none, status :
     enum<received,timeout,finished>>
     Receive a data item with a timeout. A negative timeout parameter means infinite
     waiting. It returns a tuple with the following possible values:
       *  (data, $received);
       *  (none, $timeout);
       *  (none, $finished);
     
  *  select( group :list<@T>, timeout = -1.0 ) => tuple<selected: none|@T, value :any, 
     status :enum<selected,timeout,finished>>
     Select on a group of channels, wait with a timeout for data become available from
     any of the channels. It returns a tuple with the following possible values:
       *  (channel, data, $selected);
       *  (none, none, $timeout);
       *  (none, none, $finished);
     As the signature indicates, this is a static method.


Here is a simple example, where integers are sent through one channel and strings through
another, and these integers and strings are received using the select method:
     
   1  load sys
   2  
   3  chans = { mt::channel<int>(1), mt::channel<string>(1) }
   4  
   5  mt.start {
   6      index = 0;
   7      while( ++index <= 10 ){
   8          if( rand(2) ){
   9              io.writeln( "sending integer:", index );
  10              chans[0].send( index )
  11          }else{
  12              io.writeln( "sending string: S" + (string) index );
  13              chans[1].send( 'S' + (string) index )
  14          }   
  15          sys.sleep(0.5)
  16      }   
  17      # set channel buffer sizes to zero to close them:
  18      chans[0].cap(0) 
  19      chans[1].cap(0)
  20  }
  21  
  22  while( 1 ){
  23      data = mt::channel::select( chans, 0.2 )
  24      io.writeln( "received:", data );
  25      if( data.status == $finished ) break
  26  }