280 likes | 430 Views
From Objects to Actors. Study of a Limited Symbiosis in Smalltalk-80. Actalk. Minimal extension needed to introduce and study concurrency Jean-Pierre Briot. Goals. Preservation No change made to Smalltalk-80 Minimality Extensibility Synergy
E N D
From Objects to Actors Study of a Limited Symbiosis in Smalltalk-80
Actalk • Minimal extension needed to introduce and study concurrency • Jean-Pierre Briot
Goals • Preservation • No change made to Smalltalk-80 • Minimality • Extensibility • Synergy • The current model of objects and the extended set of actors should be compatible and able to cooperate • Pedagogy
Computation Model of Smalltalk-80 • Synchronous communication • A single thread of activity which is passed among objects in a call/return fashion when sending messages. • The sender is waiting for the reply from the receiver and remains blocked until this moment. • Some tools for concurrency • Processus + semaphores
Computation Model of Smalltalk-80 • Environment of computation • The environment of the object • Bindings of instance variables, class variables... • The environment of the message. • Bindings of parameters • The global environment • Blocks • Closure mechanism • Delayed evaluation and abstraction • Control structures
Computation Model of Smalltalk-80 • Multiple activities • Process • Semaphores • To protect the internal state of an object that is shared by multiple processes
From passive to active objects • An active object is able to decide when and how it will compute the messages • A serializer encapsulates an object and serializes the incoming messages in a message queue • Actor = a serialized and active object.
Message queue Object Actor Modeling an actor as a serialized object
mailbox aself behavior Implementing Actors in ST-80 • Two classes : Actor and ActorBehavior • Any ST-80 object may be used as a behavior of a new actor if its class is a subclass of ActorBehavior • A background process will be created when creating the actor to implement the autonomy of the behavior of the actor.
The class Actor EOBject subclass: #Actor instanceVariableNames: ‘mailbox behavior’ classVariableNames: ‘’ poolDictionaries: ‘’ Category ‘Actors’ !Actor methodFor: ‘initialization’! initialize mailbox := SharedQueue new initializeBehavior: aBehavior behavior := aBehavior. behavior initializeAself: self !Actor methodFor: ‘iv access’! mailbox ^mailbox !Actor methodFor: ‘message passing’! asynchronousSend: aMessage mailbox nextPut: aMessage
The (meta)class of Actor Actor class instanceVariableNames: ‘’ !Actor class methodFor: ‘instance creation and initialization’! behavior: aBehavior ^self new initializeBehavior: aBehavior new ^super new initialize
The class ActorBehavior OBject subclass: #ActorBehavior instanceVariableNames: ‘aself’ classVariableNames: ‘’ poolDictionaries: ‘’ Category ‘Actors’ !ActorBehavior methodFor: ‘initialization’! initializeAself: anActor aself := anActor. self setProcess setProcess [[true] whileTrue: [self acceptNextMessage]] fork !ActorBehavior methodFor: ‘message acceptance’! acceptNextMessage self acceptMessage: aself mailbox next acceptMessage: aMessage self performMessage: aMessage The process is suspended and resumed when there is a message by the semaphore synchronizing the availability of message(s) in the shared queue
Support Method !Object methodFor: ‘message handling’! performMessage: aMessage ^self perform: aMessage selector arguments: aMessage arguments
Example: the class Counter ActorBehavior subclass: #Counter instanceVariableNames: ‘value’ classVariableNames: ‘’ poolDictionaries: ‘’ Category ‘Actors’ !Counter methodFor: ‘script’! incr value := value + 1 reset value := 0 !Counter class methodFor: ‘examples’! example | aCounter aCounterActor | aCounter := Counter new. aCounter reset; incr; incr; aCounterActor := Actor behavior: Counter new reset aCounterActor asynchronousSend: (Message selector: #incr)
Transparent Asynchronous Message Passing !Actor methodFor: ‘message passing’ ! doesNotUnderstand: aMessage self asynchronousSend: aMessage
The class EObject EObject subclass: #Actor instanceVariableNames: ‘’ classVariableNames: ‘’ poolDictionaries: ‘’ Category ‘Encapsulator’ !EObject class methodFor: ‘initialization’! initialize self superclass: nil. #( doesNotUnderstand: error: ~~ isNil = == printString printOn: class inspect basicInspect basicAt: basicSize instVarAt: instVarAt:Put) do: [ :selector | Object copyMethodSelector: selector inClass: self] !EObject class methodFor: ‘superclass access’! superclass: aClass superclass := aClass EObject initialize
Support Method !Class methodFor: ‘recopying method’! copyMethodSelector: selector inClass: self class compile: (self sourceCodeAt: selector) classified: (self whichCategoryIncludeSelector: aSelector)
How to create an actor ? !ActorBehavior methodFor: ‘actor creation’! 1st choice : create an actor from an instance of ActorBehavior actor ^Actor behavior: self 2nd choice : creating an actor from the model of behavior by redefining the new method new ^Actor behavior: super new 3nd choice : creating an actor from the model of behavior by creating a new selector newActor ^Actor behavior: self new
Compatibility with initialization !Counter class methodFor: ‘instance creation’! new ^super new reset !Counter class methodFor: ‘instance creation and initialization’! contents: anInteger ^self new contents: anInteger !Counter methodFor: ‘iv access’! contents: anInteger contents := anInteger What happens for each of the three approaches to actor creation?
Actor Framework ExtendedActorBehavior methodfor: ‘generic scheduling control’ scheduleAfterAcceptedMessage! scheduleAfterPerformedMessage! scheduleAfterReceivedMessage! ! ExtendedActorBehavior methodfor: ‘generic scheduling control’ acceptMessage: aMessage self scheduleAfterAcceptedMessage. super acceptMessage: aMessage. self scheduleAfterPerformedMessage! ! ExtendedActor methodsFor: ‘message passing’ asynchronousSend: aMessage super asynchronousSend: aMessage. behavior scheduleAfterReceivedMessage
Redefining scheduling • update user interface Counter methodFor: ‘scheduling control’ scheduleAfterPerformedMessage self changed. Processor yield
Symbiosis between objects and actors • Sending a message to an actor • Interpreted as asynchronous send • Sending a message to objects • Synchronous control • The target of the message defines the semantics of message passing
Delegation • Sub-computation can be passed on by an actor to another actor which continues the processing. • Delegation promotes modularity of the code.
Reply Destination and Delegation ActorBehavior subclass: #Printer instanceVariableNames: ‘’ classVariablesNames: ‘’ poolDIctionaries: ‘’ category: ‘Actor-Examples’ !Printer methodFor: ‘script’! reply: value Transcript show: ‘> ‘, value printString; cr! ! Printer class methodsFor: ‘initialization’! intialize Smalltalk at: #Print put: self new actor! ! Printer initialize!
Reply Destination and Delegation !Counter methodFor: ‘script’ consultAndReplyTo: replyDestination replyDestination reply: contents! ! !Counter class methodsFor: ‘example’! example (Counter contents: 100) actor incr; incr; consultAndReplyTo: Print! !
Exploitation of ConcurrencyThe Prime Number Example ActorBehavior subclass: #PrimeGenerator instanceVariables: ‘firstPrimeFilter’ initialize firstPrimeFilter := (PrimeFilter n: 2) actor upTo: max 2 to: max do: [:i | firstPrimeFilter filter: i] PrimeGenerator class new ^super new initialize example PrimeGenerator new actor upTo: 100
Exploitation of ConcurrencyThe Prime Number Example ActorBehavior subclass: #PrimeFilter instanceVariables: ‘n next’ n: aPrimeNumber n := aPrimeNumber filter: i i \\ n = 0 ifFalse: [next isNil ifTrue: [Print reply: i. next := (PrimeFilter n: i) actor] ifFalse: [next filter: i]] PrimeFilter class n: n ^self new n: n
References • Briot, Jean-Pierre, From Objects to Actors: Study of a Limited Symbiosis in Smalltalk-80, LITP 88-58 RXF, Université Pierre et Marie Curie, France, sept. 1988.