Common Lisp Actor System
Naveen Sundar G February 20, 2010
Contents
1 Introduction 2 1.1 Prerequisites ...... 2
2 Overview 2
3 Tutorial 3 3.1 Stateless Actors ...... 3 3.2 Actors with State ...... 3 3.3 Message passing ...... 4
4 Syntax 4
5 Dynamic Change of Behavior 5
6 Examples 6 6.1 Join Continuation ...... 6 6.2 Reference Cell ...... 7 6.3 Mutual Exclusion ...... 8 6.4 Dining Philosophers ...... 9
7 More Resources 10
8 Future Work 10 1 Introduction
This document describes a simple to use Actor extension for Common Lisp. The Actor Model is a concurrent model of computation in which actors, which are inde- pendent computational processes, are the basic units of computation. Computation proceeds by message passing across actors. For more on the Actor model of compu- tation please see [A+86, Var10]. In the CLAS extension for Common Lisp each actor get its own thread of execution which can be reused. My implementation has been inspired by the SALSA Actor-based distributed programming language:
http://wcl.cs.rpi.edu/salsa/
CLAS has been tested on examples found in [Var10]. The current state of the software is experimental, but I hope to improve it and add distrubtion and mobility. The code for these examples can be found in the source distribution. This manual contains a brief tutorial, an explanation of the syntax of CLAS , shows how to change the behavior of actors dynamically and explains the examples to some extent.
1.1 Prerequisites CLAS requires the Bordeaux-Threads package to work. The package along with in- structions for installation can be found at:
http://common-lisp.net/project/bordeaux-threads/.
2 Overview
Creating an actor class or template is similar to defining a function. • ( defactor Actor Class ( s t a− t e ) ( message vars ) behavior−next)
Creating an actor instance is done using the following syntax. This can be • thought of as coarsely equivalent to the new operator in Java. ( setq my actor (Actor Class (:state var 1 va lue 1 . . . − : state− var n value− n ) ) ) −
2 Sending a message • ( send my actor message arg1 ... message argn ) −
3 Tutorial
3.1 Stateless Actors A simple printer actor class with no state can be created as : ( defactor printer () (val) (pr val) next) A new instance is initialized as : ( s e t f print actor (printer)) − An asynchronous message can be sent to this actor as : ( send print actor ”hello ,world”) ; ” hello , world− ”
3.2 Actors with State A simple reference cell actor class can be created as follows : ( defactor cell (c) ( message) ( cond ((get ? message ) ( send (cust message) c)) (( set? message ) ( s e t f c (contents message)))) next) c holds the state of the actor. A new instance with value -1 is initialized as : ( s e t f c e l l actor (cell :c 1)) − − An asynchronous message can be sent to this actor as : ( send c e l l a c t o r ( make get print actor ) ; 1 − − − − The value of the cell is sent to the print actor which then prints it. See section 6.2 for a full implementation.
3 3.3 Message passing The code below typed into the repl illustrates use of default state variables and the message sending syntax which is similar to function calls in Lisp. We create an actor class linear which takes the linear combination of its message components x , y with its state variables a and b , ax + by and sends it to cust actor. Note we do not set the state variable b, and therefore it assumes its default value 1. CL USER> ( defactor linear (a (b 1)) (x y cust) − ( send cust (+ ( a x ) ( b y ) ) ) ) ;LINEAR ∗ ∗ CL USER> ( s e t f lin actor (linear :a 2 )) ;(#−
4 Syntax
The syntax of CLAS uses LISP s-expressions. The main macros, functions and key- words of CLAS are summarized in this section.
behav : macro • arguments : [state message &body body] Create a behavior that has state state, message format message and behavior specified by body
defactor : macro • arguments : [name state message &body body] Create an actor named name that has state state, message format message and behavior specified by body
send: function • arguments : [actor message] Send actor actor message message.
self: constant keyword • Refers to own actor.
next: constant keyword • Used to change behavior dynamically. Set by default to current behavior.
4 me: constant keyword • Refers to own behavior. This is meant to be an easy replacement of Y- combinators. Not to be used explicitly by the user.
make-actor : function • arguments : [behav] Creates an actor and returns a reference to the actor with behavior specified by behav. Not supposed to be used by the CLAS user.
5 Dynamic Change of Behavior
CLAS supports dynamic behavior by changing the behavior λ itself as formulated in the Actor Calculus. For example a cell actor is changed to a print actor as follows. ( send c e l l a c t o r ( make set 1) : next (behav () (val) (pr val) next )) − − − Behavior change is real behavior change and not a change of state variables as can be seen from above.
5 6 Examples
This section discusses examples from the Chapter 2 of [Var10] implemented in CLAS .
6.1 Join Continuation Lines 4 7 in the listing 6.1 below contain the class template for a join continuation actor which− becomes sink at the end of computation. Join Continuation for Tree Product
1 ( defun left (tree) ( first t r e e ) ) 2 ( defun right (tree) ( second t r e e ) ) 3 ; Join 4 ( defactor joincont (customer (firstnum nil)) (message) 5 ( i f ( n u l l firstnum ) 6 ( progn ( s e t f firstnum message) next) 7 ( progn ( send customer ( firstnum message)) #’sink))) ∗ 8 9 ( defactor treeprod () (customer tree) 10 ( i f ( atom t r e e ) 11 ( send customer tree) 12 ( let ((newcust (joincont :customer customer)) 13 (lp (treeprod)) 14 (rp (treeprod))) 15 ( send lp newcust (left tree)) 16 ( send rp newcust (right tree)))) 17 next)
Create a new tree product actor ( s e t f tree actor (treeprod)) − Send message to the tree product actor, and send the result back to a printing actor. ( send tree actor print actor ’((2 3) ((4 5) (10 2)))) 2400 − −
6 6.2 Reference Cell A simple reference cell actor class can be built as shown below: Reference Cell
1 ( defactor cell (c) ( message) 2 ( cond ((get ? message ) ( send (cust message) c)) 3 (( set? message ) ( s e t f c (contents message)))) 4 next) 5 6 ( defun make set (val) ‘(”set” ,val)) − 7 ( defun make get (cust) ‘(”get” ,cust)) − 8 9 ( defun get? (message) ( equal ( first message) ”get”)) 10 ( defun set? (message) ( equal ( first message) ”set”)) 11 12 ( defun cust (message) ( second message ) ) 13 ( defun contents (message) ( second message ) )
A new instance with value 7 is initialized as : ( s e t f c e l l actor (cell :c 0)) − Messages can be sent as follows: ( let ((a (cell :c 0))) ( send a ( make set 7 ) ) ( send a ( make−set 2 ) ) ( send a ( make−get print actor ) ) ) − −
7 6.3 Mutual Exclusion A semaphore actor class and a customer actor class are shown in listing 6.3
Mutual Exclusion
1 ( defactor sem ((h nil)) (m) 2 ( i f ( get ? m) 3 ( i f ( n u l l h) 4 ( progn ( send ( cust m) t ) 5 ( s e t f h ( cust m) ) 6 next) 7 ( progn ( send (cust m) nil) 8 next )) 9 (if (release? m) 10 ( progn ( s e t f h n i l ) next) 11 next ))) 12 13 ( defactor customer (semaphore) (m) 14 ( i f m 15 (progn (pr ”Critical code”) 16 ( send semaphore (make release ) ) ) − 17 ( send semaphore (make get s e l f ))) − 18 next) 19 20 ( defun make release () ‘(”release” )) − 21 ( defun make get (cust) ‘(”get” ,cust)) − 22 23 ( defun get? (message) ( equal ( first message) ”get”)) 24 ( defun release? (message) ( equal ( f i r s t message) ”release”)) 25 26 ( defun cust (message) ( second message ) )
Two actors trying to enter a critical region can be modeled as ( let ( ( s ( sem ) ) (a1 (customer :semaphore s)) (a2 (customer :semaphore s))) ( send a1 n i l ) ( send a2 n i l ) )
8 6.4 Dining Philosophers The philosopher actor class and the chopstick actor class are show in listing 6.4
Mutual Exclusion
1 ( defactor phil (l r (sticks 0)) (m) 2 ( i f ( zerop s t i c k s ) 3 ( progn 4 (pr ”Got one”) 5 ( i n c f s t i c k s ) next) 6 ( progn 7 (pr ”Got both”) 8 ( send l ( make drop s e l f ))( send r ( make drop s e l f )) − − 9 (pr ”Dropped”) 10 ( send l ( make pick s e l f ))( send r ( make pick s e l f )) − − 11 ( s e t f s t i c k s 0) next ))) 12 13 ( defactor chopstick ((h nil) (w nil)) (m) 14 (if (pick? m) 15 ( i f ( n u l l h) 16 ( progn ( send ( get phil m) n i l ) − 17 ( s e t f h ( get phil m) w nil) − 18 next) 19 ( progn ( s e t f w ( get phil m) ) − 20 next ))) 21 (if (drop? m) 22 ( i f ( n u l l w) 23 ( progn ( s e t f w n i l h n i l ) 24 next) 25 ( progn ( send w n i l ) 26 ( s e t f h w w n i l ) ) ) ) 27 next) 28 29 ( defun make drop (cust) ‘(”drop” ,cust)) − 30 ( defun make pick (cust) ‘(”pick” ,cust)) − 31 ( defun pick ? ( x ) ( equal ( first x ) ” pick ” ) ) 32 ( defun drop ? ( x ) ( equal ( first x ) ”drop” ) ) 33 ( defun get phil (m) ( second m) ) −
New philosophers and chopsticks are created as follows ( let ((c1 (chopstick)) ∗ (c2 (chopstick)) (p1 (phil :l c1 :r c2)) (p2 (phil :l c2 :r c1))) ( send c1 ( make pick p1 ) ) − 9 ( send c2 ( make pick p1 ) ) ( send c1 ( make−pick p2 ) ) ( send c2 ( make−pick p2 ) ) ) −
7 More Resources
The CLAS system can be downloaded from GitHub:
http://github.com/naveensundarg/Common-Lisp-Actors
Miscellaneous stuff:
http://www.cs.rpi.edu/~govinn/clas.html This manual can be found at :
http://www.cs.rpi.edu/~govinn/actors.pdf
8 Future Work
I plan to implement distribution and mobility of actors in CLAS . The only major issue, that I foresee, is serialization of Common Lisp objects, but this can be overcome by explicitly stating which objects are serializable.
References
[A+86] G.A. Agha et al. Actors: a model of concurrent computation in distributed systems. MIT press Cambridge, MA, 1986.
[Var10] C. Varela. Distributed Computing: A Foundational Approach. MIT Press, 2010.
10