@c =================================================================== @c
@c    serrano/prgm/project/bigloo/manuals/fthread.texi                 @c
@c    ------------------------------------------------------------     @c
@c    Author      :  Manuel Serrano                                    @c
@c    Creation    :  Mon Jun 15 15:09:03 1998                          @c
@c    Last change :  Mon Nov 12 15:11:18 2001 (serrano)                @c
@c    ------------------------------------------------------------     @c
@c    The Bigloo Fair threads                                          @c
@c =================================================================== @c

@c ------------------------------------------------------------------- @c
@c    Bigloo's threads                                                 @c
@c ------------------------------------------------------------------- @c
@node Fair Threads, Posix Threads, Thread Common Functions, Threads
@comment  node-name,  next,  previous,  up
@section Threads
@cindex Fair Threads
@cindex Threads

Bigloo supports fair threads (see Section @ref{Thread}), a
specification of cooperative threads. In this framework a thread must
explicitly or implicitly @emph{yield} the processor to the scheduler
(see Section @ref{Scheduler}). Explicit cooperation is achieved by
library functions such as @code{thread-yield!} or
@code{thread-sleep!}. The scheduler @b{does not preempt a running thread} to 
allocate the processor to another waiting thread. Fair threads have two
drawbacks over preemptive threads:

@itemize @bullet
@item Cooperative threads are not able to benefit of multi-processors
      platforms.
@item Single threads programs must be adapted in order to be run 
      concurrently. 
@end itemize

On the other hand, Fair threads have advantages that make them
suitable for a high level programming language such as Scheme:

@itemize @bullet
@item Fair threads have a strong and well defined semantic. Multi threaded
      programs using Fair threads are @emph{deterministic} thus programs
      that deploy Fair threads are @emph{predictable}.
@item Fair threads are easier to program with because they hide most the
      of the concurrent programming pitfalls. In particular, since Fair
      threads enforce a strong synchronization, there
      is no need to deploy techniques such as @emph{mutex}, @emph{semaphore}
      or @emph{condition variables}.
@end itemize

@menu
* Introduction::
* Fair Threads Api::
* SRFI-18 compatibility::
@end menu

This whole chapter has been written in collaboration with @b{F.
Boussinot}. It uses materials on Fair threads that can be found at
@url{http://www-sop.inria.fr/indes/rp/FairThreads/html/FairThreads.html}.

@c -- Introduction --------------------------------------------------- @c
@node Introduction, Fair Threads Api, , Fair Threads
@comment  node-name,  next,  previous,  up
@subsection Introduction to Fair Threads

Fair threads are cooperative threads run by a fair scheduler which
gives them equal access to the processor. Fair threads can communicate
using broadcast events. Their semantics does not depends on the
executing platform. Fine control over fair threads execution is
possible allowing the programming of specific user-defined scheduling
strategies. 

Contrary to standard sequential programming where the processor
executes a single program, in concurrent programming the processor is
a shared resource which is dispatched to several programs. The term
@emph{concurrent} is appropriate because programs can be seen as
concurrently competing to gain access to the processor, in order to
execute.

Threads are a basic means for concurrent programming, and are widely
used in operating systems. At language level, threads offer a way to
structure programs by decomposing systems in several concurrent
components; in this respect, threads are useful for modularity.

However, threads are generally considered as low-level primitives
leading to over-complex programming. Moreover, threads generally have
loose semantics, in particular depending on the underlying executing
platform; to give them a precise semantics is a difficult task, and
this is a clearly identified problem to get portable code.

Bigloo proposes a new framework with clear and simple semantics, and
with an efficient implementation. In it, threads are called
@emph{fair}; basically a fair thread is a cooperative thread executed
in a context in which all threads always have equal access to the
processor. Fair threads have a deterministic semantics, relying on
previous work belonging to the so-called reactive approach.

@c -- API ------------------------------------------------------------ @c
@node Fair Threads Api, SRFI-18  compatibility, Introduction, Fair Threads
@comment  node-name,  next,  previous,  up
@subsection Fair Threads Api

@menu
* Thread::
* Scheduler::
* Signal::
@end menu

The Fair Thread library relies on the Posix Thread one, but you don't
need to import the @code{pthread} library, as it is done automatically
when importing the @code{fthread} one.

The functions listed in @ref{Thread Common Functions} can be used to
manipulates the Fair Thread, but @code{thread-start-joinable!}, as
a fair thread can always join any other fair thread in the same
scheduler.

@c -- threads -------------------------------------------------------- @c
@node Thread, Scheduler, ,Fair Threads Api
@subsubsection Thread

@deffn {Bigloo syntax} instantiate::fthread (body @var{thunk}) [(name @var{name})]
Returns a new thread which is not started yet. The body of the thread
is the body of the procedure @var{thunk}. The optional argument @var{name}
can be use to identify the thread. It can be any Bigloo value.

@smalllisp
(instantiate::fthread (body (lambda () (print 1) (thread-yield!)
(print 2)))
                      (name 'my-thread))
@end smalllisp

The former thread-start function can be rewritten as follow:

@smalllisp
(define (make-thread body . name)
  (if (pair? name)
      (instantiate::fthread (body body) (name (car name)))
      (instantiate::fthread (body body))))
@end smalllisp
@end deffn

@deffn {SRFI-18 function} thread-start! @var{thread} [@var{scheduler}]
Runs a thread created with @code{make-thread}. If @var{scheduler} is
provided, the @var{thread} is started in this particular scheduler. Otherwise,
it is started in the current scheduler (see Section @ref{Scheduler}).
Threads are started at the beginning of @emph{reactions} 
(see Section @ref{Scheduler}).
@end deffn

@deffn {SRFI-18 function} thread-yield!
The current thread @emph{cooperates}. That is, it is suspended for the
@emph{reaction} and the scheduler selects a new thread to be resumed. The
scheduler resumes the next avaliable thread. If there is only one
thread started in the scheduler, the same thread is resumed. 
A @emph{reaction} corresponds to the invocation of a @code{scheduler-react!}
call (see Section @ref{Scheduler}).
@end deffn

@deffn {SRFI-18 function} thread-sleep! @var{timeout}
The current thread @emph{cooperates} during @emph{exactly} @var{timeout}
@emph{reactions} (see @ref{Scheduler}). It is suspended and the scheduler 
selects a new thread to be resumed. If there is only one thread started in the
scheduler, the same thread will be resumed.

@smalllisp
(let ((t1 (instantiate::fthread
             (body (lambda () (thread-sleep! 2) (display 'foo)))))
      (t2 (instantiate::fthread
             (body (lambda () (let loop ((n 1))
                                 (display n) 
                                 (thread-yield!)
                                 (if (< n 5)
                                 (loop (+ n 1)))))))))
   (thread-start! t1)
   (thread-start! t2)
   (scheduler-start!)) @print{} 12foo34
@end smalllisp
@end deffn

@deffn {SRFI-18 function} thread-terminate! @var{thread}
Terminates @var{thread} at the end of the current reaction.
@end deffn

@deffn {SRFI-18 function} thread-join! @var{thread} [@var{timeout} [@var{timeout-val}]]
The current thread waits until @var{thread} terminates or until
@var{timeout} is reached (when supplied). If the @var{timeout} is
reached, @code{thread-join!} returns @var{timeout-val}. If @var{thread}
terminates, @code{thread-join!} returns the end-result of the @var{thread}
or the end-exception if that thread terminates abnormally.

If several threads wait for the termination of the same thread, they are
all notified of the termination during the current reaction.

@smalllisp
(let* ((t1 (thread-start!
            (instantiate::fthread
               (body (lambda () (thread-sleep! 3) 'foo)))))
       (t2 (thread-start!
            (instantiate::fthread
               (body (lambda () (print "t1: " (thread-join! t1 1)))))))
       (t3 (thread-start!
            (instantiate::fthread
               (body (lambda () (print "t2: " (thread-join! t1 2 'bar)))))))
       (t3 (thread-start!
            (instantiate::fthread
               (body (lambda () (print "t3: " (thread-join! t1)))))))
       (t4 (thread-start!
            (instantiate::fthread
               (body (lambda () (print "t4: " (thread-join! t1))))))))
   (scheduler-start!))
   @print{} t1: #|%uncaught-exception [reason: (exception . join-timeout)]|
      t2: bar
      t3: foo
      t4: foo
@end smalllisp

@code{thread-join!} can be used to wait for a Posix Thread
termination. The @code{pthread} object must be started with
@code{thread-start-joinable!}.
@end deffn

@deffn {Bigloo function} thread-suspend! @var{thread}
@deffnx {Bigloo function} thread-resume! @var{thread}
Suspends/resumes the @var{thread} at the end of reaction. While suspended
a thread is not eligible to get the processor by the scheduler. 
@end deffn

@deffn {Bigloo function} thread-await! @var{signal} [@var{timeout}]

Blocks the thread until @var{signal} has been broadcast or until
@var{timeout} has elapsed. The function @code{thread-await!} returns
the value associated with the previous emissions of the signal that
took place during the reaction.

@smalllisp
(let ((t1 (thread-start! (instantiate::fthread
                            (body (lambda ()
                                     (display (thread-await! 'foo))
                                     (display (thread-await! 'bar)))))))
      (t2 (thread-start! (instantiate::fthread
                            (body (lambda ()
                                     (broadcast! 'foo 'val1-foo)
                                     (broadcast! 'foo 'val2-foo))))))
      (t3 (thread-start! (instantiate::fthread
                            (body (lambda ()
                                     (thread-sleep! 2)
                                     (broadcast! 'bar 'val-bar)))))))
   (let loop ((n 1))
      (display n)
      (scheduler-react! (default-scheduler))
      (loop (+ n 1))))
  @print{} 1val2-foo23val-bar456...
@end smalllisp

The function @code{thread-await!} cannot be used to intercept all the signals
broadcast during a reaction. This is illustrated by the following example
where obviously @code{thread-await!} cannot intercept the emission of the
signal:

@smalllisp
(thread-start! (instantiate::fthread (body (lambda () 
                                              (thread-await! 'foo)
                                              (broadcast! 'foo 1)))))
(thread-start! (instantiate::fthread (body (lambda () 
                                              (broadcast! 'foo 2)))))
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-get-values! @var{signal}

Terminates the instant for the thread (as @code{thread-yield!}) and
returns, hence at the next instant, all the values associated with
broadcast @var{signal} (see Section @ref{Signal}) during the previous scheduler
reaction (see Section @ref{Scheduler}).

Example:
@smalllisp
(thread-start! (instantiate::fthread
                  (body (lambda ()
                           (for-each print (thread-get-values! 'foo))))))
(thread-start! (instantiate::fthread
                  (body (lambda ()
                           (broadcast! 'foo 1)
                           (broadcast! 'foo 'foo)
                           (broadcast! 'foo "blabla")))))
   @print{} 1
      foo
      blabla
@end smalllisp

Example:
@smalllisp
(let ((t1 (thread-start!
           (instantiate::fthread
              (body (lambda ()
                       (for-each print (thread-get-values! 'foo))))
              (name 't1))))
      (t2 (thread-start!
           (instantiate::fthread
              (body (lambda ()
                       (broadcast! 'foo (current-thread))
                       (thread-yield!)
                       ;; this second broadcast won't be intercepted 
                       ;; because it occurs during the next reaction
                       (broadcast! 'foo (current-thread))))
              (name 't2))))
      (t3 (thread-start!
           (instantiate::fthread
              (body (lambda ()
                       (broadcast! 'foo (current-thread))
                       (broadcast! 'foo (current-thread))))
              (name 't3)))))
   (scheduler-start!))
   @print{} #<thread:t2>
      #<thread:t3>
      #<thread:t3>
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-await-values! @var{signal} [@var{timeout}]
This blocks the current thread until @var{signal} has been broadcast.
It then returns, at the next instant, all the values associated with
all the broadcasts that took place during the instant.
It can be defined as:

@smalllisp
(define (thread-await-values! signal . tmt)
   (apply thread-await! signal tmt)
   (thread-get-values signal))
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-await*! @var{signals} [@var{timeout}]
@cindex select (unix-like)
Wait for one of a list of signals. The function @code{thread-await*!}
can be compared to the Unix @code{select} function. The argument 
@var{signals} is a list of signal identifier. The function 
@code{thread-await*!} blocks the current thread until one of the signal in 
the list @var{signals} is broadcast or until the optional numerical argument 
@var{timeout} is elapsed. If the thread unblocks because the timeout is 
elapsed, @code{thread-await*!} returns @code{#f}. Otherwise it returns two
values that have to be collected with @code{multiple-value-bind} (see
@ref{Control Features}). The first one is the value of the broadcast
signal. The second one is the broadcast signal.

Example:
@smalllisp
(let ((res #f))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (let ((sig* (list 'foo 'bar)))
                   (multiple-value-bind (val1 sig1)
                      (thread-await*! sig*)
                      (multiple-value-bind (val2 sig2)
                         (thread-await*! sig*)
                         (thread-yield!)
                         (multiple-value-bind (val3 sig3)
                            (thread-await*! sig*)
                            (set! res (list sig1 sig2 sig3))))))))))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-sleep! 2)
                (broadcast! 'foo 1)))))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-sleep! 3)
                (broadcast! 'bar 2)))))
   (scheduler-start!)
   res)
  @result{} '(foo foo bar)
@end smalllisp

A second example using timeouts:
@smalllisp
(let ((res #f))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (let ((sig* (list 'foo 'bar)))
                   (multiple-value-bind (val1 sig1)
                      (thread-await*! sig* 1)
                      (thread-yield!)
                      (multiple-value-bind (val2 sig2)
                         (thread-await*! sig* 1)
                         (thread-yield!)
                         (multiple-value-bind (val3 sig3)
                            (thread-await*! sig* 2)
                            (set! res (list sig1 sig2 sig3))))))))))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-sleep! 2)
                (broadcast! 'foo 1)))))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-sleep! 3)
                (broadcast! 'bar 2)))))
   (scheduler-start!)
   res)
  @result{} '(#f foo bar)
@end smalllisp
@end deffn

@deffn {Bigloo function} thread-get-values*! @var{signals}
Terminates the instant for the thread (as @code{thread-yield!}) and
returns, hence at the next instant, all the values associated with
all broadcast @var{signals} (see Section @ref{Signal}) during the previous 
scheduler reaction (see Section @ref{Scheduler}). The function 
@code{thread-get-values*!} returns an @emph{alist} made of the scanned signal
and their values. That is the length of the returns list is the length
of the list @var{signals}. If a signal of the list @var{signals} has not
been broadcast, its associated entry the list returned by 
@code{thread-get-values*!} has an empty @code{cdr}.

Example:
@smalllisp
(let ((s1 'foo)
      (s2 'bar)
      (s3 'gee)
      (res #f))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-sleep! 2)
                (broadcast! 'foo (current-time))
                (broadcast! 'bar 0)))))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-await*! (list s1 s2 s3))
                (set! res (thread-get-values*! (list s1 s2 s3)))))))
   (thread-start!
    (instantiate::fthread
       (body (lambda ()
                (thread-sleep! 2)
                (broadcast! 'bar (current-time))))))
   (scheduler-start!)
   res)
  @result{} ((foo 3) (bar 3 0) (gee))
@end smalllisp

Used with asynchronous signal, the functions @code{thread-await*!} and
@code{thread-get-values*!} can be used to read concurrently, in a non 
blocking way, several files. 
@end deffn

@deffn {Bigloo function} thread-await-values*! @var{signals} [@var{timeout}]
This blocks the current thread until at least one of @var{signals} has 
been broadcast. It then returns, at the next instant, all the values associated
with all the broadcasts that took place during the instant. It can be 
defined as:

@smalllisp
(define (thread-await-values*! signal . tmt)
   (apply thread-await*! signal tmt)
   (thread-get-values*! signal))
@end smalllisp
@end deffn


@c -- Scheduler ------------------------------------------------------ @c
@node Scheduler, Signal, Thread, Fair Threads Api
@subsubsection Scheduler

@deffn {Bigloo function} make-scheduler [@var{strict-order?}] [@var{envs}]
Creates a new scheduler. The optional boolean argument
@code{strict-order?} is used to ask the scheduler to always schedule
the threads in the same order, it defaults to @code{#f}. The optional
arguments @var{envs} are @emph{fair thread environments} which will be
defined in forthcoming Bigloo releases.
@end deffn

@deffn {Bigloo function} scheduler-strict-order?
@deffnx {Bigloo function} scheduler-strict-order?-set! @var{bool}
Gets or sets the strict scheduling policy of the scheduler. If set,
the threads will always be scheduled in the same order, until their
termination. By default, it is set to false, which improve
performances when there is a lot of thread to schedule.
@end deffn

@deffn {Bigloo function} scheduler? @var{obj}
Returns @code{#t} if @var{obj} is a scheduler. Otherwise returns @code{#f}.
@end deffn

@deffn {Bigloo function} scheduler? @var{obj}
Returns @code{#t} if @var{obj} is a scheduler. Otherwise returns @code{#f}.
@end deffn

@deffn {Bigloo function} current-scheduler
Returns the current scheduler. The current scheduler is the scheduler
which currently schedules the current thread. This value is not
mutable, as it is set during the call to @code{thread-start!}.
@end deffn

@deffn {Bigloo function} default-scheduler [@var{scheduler}]
Sets or gets the default scheduler. The default scheduler is the
scheduler that will be used in the calls to @code{scheduler-react!},
@code{scheduler-start!} or @code{thread-start!} if not specified.
It always exists a default scheduler. That is, it is optional for an
application to create a scheduler.
@end deffn

@deffn {Bigloo function} scheduler-react! [@var{scheduler}]
Executes all the threads started (see @code{thread-start!}, 
Section @ref{Thread}) in the scheduler until all the threads are
blocked. A thread is blocked if the has explicitly yield the processor 
(@code{thread-yield!} and @code{thread-sleep!}) or because it is waiting
a signal (@code{thread-await!}). A thread
can be selected several times during the same reaction.
The function @code{scheduler-react!} returns a symbol denoting the
@emph{state} of the scheduler. The possible states are:

@itemize @bullet
@item @code{ready} The Scheduler is ready to execute some threads.
@item @code{done} All the threads started in the scheduler have terminated.
@item @code{await} All the threads  started in the scheduler are waiting for
      a signal.
@end itemize

An invocation of @code{scheduler-react!} is called a @emph{reaction}.
@end deffn

@deffn {Bigloo function} scheduler-start! [@var{arg} [@var{scheduler}]]
Executes @code{scheduler-react!} as long as the scheduler is not done.
If the optional argument @var{scheduler} is not provided, 
@code{scheduler-start!} uses the current scheduler 
(see @code{current-scheduler}). The optional @var{arg} can either be:
@itemize @bullet
@item An integer standing for the number of times @code{scheduler-react!}
      must be called.
@item A procedure @var{f} of one argument. The procedure @var{f}
      is invoked after each reaction. It is passed a value @var{i} which is 
      the iteration number of the scheduler. The reactions of the scheduler
      continue while @var{f} returns @code{#f}.
@end itemize

@smalllisp
(let* ((s (make-scheduler))
       (t (instantiate::fthread
             (body (lambda () 
                      (let loop ((n 0))
                         (display n)
                         (thread-yield!)
                         (loop (+ 1 n))))))))
   (scheduler-start! 10 s))
  @print{} 0123456789

(let* ((s (make-scheduler))
       (t (instantiate::fthread
             (body (lambda () 
                      (let loop ((n 0))
                         (display n)
                         (thread-yield!)
                         (loop (+ 1 n))))))))
   (scheduler-start! (lambda (i) (read-char)) s))
  @print{} 0123456789
@end smalllisp
@end deffn

@deffn {Bigloo function} scheduler-terminate! [@var{scheduler}]
Terminates all the threads in @var{scheduler}.
@end deffn

@deffn {Bigloo function} scheduler-instant [@var{scheduler}]
Returns the current reaction number of @var{scheduler}. The reaction
number is the number of times @code{scheduler-react!} has been invoked
passing @var{scheduler} as argument.
@end deffn

@c -- Signal --------------------------------------------------------- @c
@node Signal, , Scheduler, Fair Threads Api
@subsubsection Signal

@deffn {Bigloo function} broadcast! @var{signal} [@var{val}]
Broadcasts @var{signal} to all threads started in @var{scheduler} 
@emph{immediately}, that is during the reaction. This function can only
be called from within a running thread. If the optional argument @var{val}
is omitted, the @var{signal} is broadcast with an unspecified value.

@smalllisp
(thread-start! (instantiate::fthread
                  (body (lambda ()
                           (thread-await! 'foo)
                           (print (scheduler-instant (current-scheduler)))))))
(thread-start! (instantiate::fthread
                  (body (lambda ()
                           (broadcast! 'foo)))))
(scheduler-start!)
  @print{} 1
@end smalllisp
@end deffn

@deffn {Bigloo function} scheduler-broadcast! @var{scheduler} @var{signal} [@var{val}]
At the next react broadcasts @var{signal} to all threads started 
in @var{scheduler}. This is used to impact running threads from outside 
any threads. If the optional argument @var{val}
is omitted, the @var{signal} is broadcast with an unspecified value.
@end deffn

@deffn {Bigloo function} make-asynchronous-signal @var{proc}
@cindex asynchronous signal
@cindex Parallelism
This function invokes in the background, the procedure @var{proc}.
This function takes one parameter which is the signal that is broadcast
when the invocation returns. When the host operating system supports
parallel executions, the invocation of @var{proc} is executed in
parallel with the waiting thread. 

Asynchronous signals can be used to implement non blocking system
operations, such as input/output. Here is an example that illustrates
how to implement concurrent programs that behaves similarly with
Fair Threads and Posix Threads.

@smalllisp
(define-expander read
   (lambda (x e)
      (cond-expand
	 (fthread
	  (thread-await!
	   (make-aynchronous-signal
	    (lambda (s)
	       (read ,@@(map (lambda (x) (e x e)) (cdr x)))))))
	 (else
	  `(read ,@@(map (lambda (x) (e x e)) (cdr x)))))))
@end smalllisp
@end deffn


@c -- SRFI-18 -------------------------------------------------------- @c
@node SRFI-18 compatibility, , Fair Threads Api, Fair Threads
@comment  node-name,  next,  previous,  up
@subsection SRFI-18
@cindex SRFI-18

This section presents the functions that are not necessary to Bigloo
but supported for compliance with SRFI-18, provided by the Fair Thread
library.

@deffn {SRFI-18 function} current-time [@var{scheduler}]
Returns the reaction number of @var{scheduler}.
@end deffn

@deffn {SRFI-18 function} time? @var{obj}
@deffnx {SRFI-18 function} time->seconds @var{obj}
@end deffn

@deffn {SRFI-18 function} join-timeout-exception? @var{obj}
@deffnx {SRFI-18 function} abandoned-mutex-exception? @var{obj}
@deffnx {SRFI-18 function} terminated-thread-exception? @var{obj}
@deffnx {SRFI-18 function} uncaught-exception? @var{obj}
@deffnx {SRFI-18 function} uncaught-exception-reason @var{exc}
@end deffn
