RFC 178 (v5) Lightweight Threads

2000-09-26 Thread Perl6 RFC Librarian

This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Lightweight Threads

=head1 VERSION

  Maintainer: Steven McDougall [EMAIL PROTECTED]
  Date: 30 Aug 2000
  Last Modified: 26 Sep 2000
  Mailing List: [EMAIL PROTECTED]
  Number: 178
  Version: 5
  Status: Frozen

=head1 ABSTRACT

A lightweight thread model for Perl.

=over 4

=item *

All threads see the same compiled subroutines

=item *

All threads share the same global variables

=item *

Threads can create thread-local storage by Clocalizing global variables

=item *

All threads share the same file-scoped lexicals

=item *

Each thread gets its own copy of block-scoped lexicals upon execution
of Cmy

=item *

Threads can share block-scoped lexicals by passing a reference to a
lexical into a thread, by declaring one subroutine within the scope of
another, or with closures.

=item *

Open code can only be executed by a thread that compiles it

=item * 

The language guarantees atomic data access. Everything else is the
user's problem.

=back 

=over 4

=item Perl

Swiss-army chain saw

=item Perl with threads

juggling chain saws

=back

=head1 CHANGES

=head2 v5

Frozen

=head2 v4

=over 4

=item *

Traded in data coherence for LAtomic data access. Added examples 16 and
17. 

=item *

Traded in Primitive operations for LLocking

=item *

Dropped L/local section

=item *

Revised L/Performance section

=back

=head2 v3

=over 4

=item *

Simplified example 9

=item *

Added L/Performance section

=back

=head2 v2

=over 4

=item *

Added section on sharing block-scoped lexicals between threads

=item *

Added examples 9, 10, and 11. (N.B. renumbered following examples)

=item *

Fixed some typos

=back


=head1 FROZEN

There was substantial--if somewhat disjointed--discussion of thread
models on perl6-internals. The consensus among those with internals
experience is that this RFC shares too much data between threads, and
that the CPU cost of acquiring a lock for every variable access will
be prohibitive.

Dan Sugalski discussed some of the tradeoffs and sketched an alternate
threading model at

http://www.mail-archive.com/perl6-internals%40perl.org/msg01272.html

however, this has not been submitted as an RFC.


=head1 DESCRIPTION

The overriding design principle in this model is that there is one
program executing in multiple threads. One body of code; one set of
global variables; many threads of execution. I like this model because

=over 4

=item *

I understand it

=item *

It does what I want

=item *

I think it can be implemented

=back


=head2 Notation

=over 4

=item Imain and Ispawned threads

We'll call the first thread that executes in a program the Imain
thread. It isn't distinguished in any other way. All other threads are
called Ispawned threads.

=item Iopen code

Code that isn't contained in a BLOCK.

=back

Examples are written in Perl5, and use the thread programming model
documented in CThread.pm. Discussions of performance and
implementation is based on the Perl5 internals; obviously, these are
subject to change.


=head2 All threads see the same compiled subroutines

Subroutines are typically defined during the initial compilation of a
program. Cuse, Crequire, Cdo, and Ceval can later define
additional subroutines or redefine existing ones. Regardless, at any
point in its execution, a program has one and only one collection of
defined subroutines, and all threads see this collection.

Example 1

sub foo  { print 1 }
sub hack_foo { eval 'sub foo { print 2 }' }
foo();
Thread-new(\hack_foo)-join;
foo();

Output: 12. The main thread executes Cfoo; the spawned thread
redefines Cfoo; the main thread executes the redefined subroutine.


Example 2

sub foo  { print 1 }
sub hack_foo { eval 'sub foo { print 2 }' }
foo();
Thread-new(\hack_foo);
foo();

Output: 11 or 12, according as the main thread does or does not make
the second call to Cfoo() before the spawned thread redefines it. If
the user cares which happens first, then they are responsible for
doing their own synchronization, for example, with Cjoin, as shown
in Example 1.

Code refs (like all Perl data objects) are reference counted. Threads
increment the reference count upon entry to a subroutine, and
decrement it upon exit. This ensures that the op tree won't be garbage
collected while the thread is executing it.


=head2 All threads share the same global variables

Example 3

#!/my/path/to/perl
$a = 1;
Thread-new(\foo)-join;
print $a;

sub foo { $a++ }

Output: 2. C$a is a global, and it is the Isame global in both the
main thread and the spawned thread.


=head2 Threads can create thread-local storage by Clocalizing global
variables

Example 4

#!/my/path/to/perl
$a = 1;
Thread-new(\foo);
print $a;

sub foo { local $a = 2 }

Output: 1. The spawned thread gets it's own copy of C$a. The copy of
C$a in the main thread is unaffected. It 

RFC 185 (v3) Thread Programming Model

2000-09-26 Thread Perl6 RFC Librarian

This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Thread Programming Model

=head1 VERSION

  Maintainer: Steven McDougall [EMAIL PROTECTED]
  Date: 31 Aug 2000
  Last Modified: 26 Sep 2000
  Mailing List: [EMAIL PROTECTED]
  Number: 185
  Version: 3
  Status: Frozen

=head1 ABSTRACT

This RFC describes the programming interface to Perl6 threads. 
It documents the function calls, operators, classes, methods, or
whatever else the language provides for programming with threads.

=head1 CHANGES

=head2 v3

Frozen

=head2 v2

=over 4

=item * 

Added SYNOPSIS, and wrote a proper ABSTRACT

=item *

Detailed Casync 

=item *

Detailed sharing of lexicals between threads

=item *

Traded Mutexes back for Clock, Ctry, and Cunlock

=item *

Pushed CSemaphore, CEvent, and CTimer down into CThread::

=item *

Specified readable, writable and failure to return Events

=item *

Reworked the wait functions

=item *

Added CQueue

=back


=head1 FREEZE

There was little, if any, further discussion after version 2.


=head1 SYNOPSIS

  use Thread;
  
  $sub = sub { ... };  
  
  $thread  = new Thread \func   , @args;
  $thread  = new Thread  $sub, @args;
  $thread  = new Thread   sub { ... }, @args;
async { ... };
  $result  = join $thread;
   
  $thread  = this Thread;
  @threads = all  Thread;
  
  $thread1 == $thread2 and ...
  Thread::yield();

  critical { ... };   # one thread at a time in this block
  
  lock $scalar;
  lock @array
  lock %hash;
  lock sub;
  
  $ok = try $scalar;
  $ok = try @array
  $ok = try %hash;
  $ok = try sub;
  
  unlock $scalar;
  unlock @array
  unlock %hash;
  unlock sub;
  
  $event = auto   Thread::Event; 
  $event = manual Thread::Event;
   set$event;
   reset  $event;
   wait   $event;
  
   $semaphore = new Thread::Semaphore $initial;
  $ok= $semaphore-up($n);
   $semaphore-down;
  $count = $semaphore-count;
  
  $timer = Thread::Timer-delay($seconds);
  $timer = Thread::Timer-alarm($time);
  $timer-wait;
  
  $event = $fh-readable
  $event = $fh-writable
  $event = $fh-failure
  
  $ok = wait_all(@references);
  $i  = wait_any(@references);
  
   $queue = new Thread::Queue
   $queue-enqueue($a);
  $a = $queue-dequeue;
  $empty = $queue-empty;


=head1 DESCRIPTION

=head2 Thread

=over 4

=item I$thread = Cnew CThread \Ifunc, I@args

Executes Ifunc(I@args) in a separate thread. The return value is
a reference to the CThread object that manages the thread.

The subroutine executes in its enclosing lexical context. This means
that lexical variables declared in that context may be shared between
threads. See RFC 178 for examples.


=item I$thread = Cnew CThread I$sub, I@args

=item I$thread = Cnew CThread Csub { ... }, I@args

Executes an anonymous subroutine in a separate thread, passing it
I@args. The return value is a reference to the CThread object that
manages the thread.

The subroutine is a closure. References to variables in its lexical
context are bound when the Csub operator executes. See RFC 178 for
examples.


=item Casync BLOCK

Executes BLOCK in a separate thread. Syntactically, Casync BLOCK
works like Cdo BLOCK. Casync creates a CThread object to manage
the thread, but it does not return a reference to it. If you want the
CThread object, use one of the Cnew CThread forms shown above.

The BLOCK executes in its enclosing lexical context. This means that
lexical variables declared in that context may be shared between
threads.


=item I$thread = Cthis CThread

Returns a reference to the CThread object that manages the current
thread.


=item I@threads = Call CThread

Returns a list of references to all existing CThread objects in the
program. This includes CThread objects created for Casync blocks.


=item I$result = Cjoin I$thread

=item I@result = Cjoin I$thread

Blocks until I$thread terminates. May be called repeatedly,
by any number of threads.

Returns the last expression evaluated in I$thread. This expression
is evaluated in list context inside the thread.

If Cjoin is called in list context, it returns the entire list; if
Cjoin is called in scalar context, it returns the first element of
the list.


=item I$thread1 == I$thread2

Evaluates to true iff I$thread1 and I$thread2 reference the same
CThread object.


=item CThread::yield()

Gives the interpreter an opportunity to switch to another thread. The
interpreter is not obligated to take this opportunity, and the calling
thread may regain control after an arbitrarily short period of time.

=back


=head2 Critical section

Ccritical is a new keyword. Syntactically, it works like Cdo. 

  critical { ... }; 

The interpreter guarantees that only one thread at a time can execute
a Ccritical block.


=head2 Lock

=over 4

=item Clock I$scalar

=item Clock I@array

=item Clock I%hash

=item Clock Isub

Applies a lock to a variable.

If there are no locks applied to