Reputation: 796
This question is not about a particular problem I am having, but rather something I find difficult to wrap my head around. The context of the problem is racket classes and threads. Consider the following actor%
class which contains an actor thread, a method to queue a message in the mailbox of the thread, and a method to receive a return value (it does nothing useful and only prints it).
(struct message (source method values))
(define actor%
(class object%
(super-new)
(init-field
[actor-thread
(create-actor-thread this)])
(define/public (receive-message source method arguments)
(define message (message source method arguments))
(thread-send actor-thread message))
(define/public (receive-value value)
(displayln value))))
As a side-note, if one wanted to create an actor, they would have to first create a subclass that implements certain messages (as methods) that the actor understands. They have a mechanism to send a message (e.g. (actor-send actor 'hello 'world)
for sending a message to actor actor
that invokes method hello
with argument world
).
All actors run within their own thread, which is defined as follows. In short: it takes a message from the inbox of a thread, it gets the source (an actor), the method (a symbol), and some values (a list), and dynamically sends it to himself to invoke the appropriate method on the instantiated subclass of actor%
.
(define (create-actor-thread self)
(thread
(lambda ()
(let actor-loop ()
;#####----- Receive message -----#####
(define message (thread-receive))
(define source (message-source message))
(define method (message-method message))
(define values (message-values message))
(define return-value (dynamic-send self method values))
(send source receive-value return-value)
(actor-loop)))))
I know for a fact that the body of the invoked message is processed in the context of the new thread, but how does this work from a concurrency perspective for the actor? Meanwhile, while the actor thread is doing heavy work, the actor can keep queuing messages in the thread's mailbox. The thing I cannot wrap my head around (or can find a reasonable explanation for) is that the actor object seems to live in two contexts: the original context, and the context of the actor thread. Both can access the same object. Is there a false sense of concurrency, or is there some magic making this all work nicely?
Upvotes: 1
Views: 157
Reputation: 8523
The thing I cannot wrap my head around (or can find a reasonable explanation for) is that the actor object seems to live in two contexts: the original context, and the context of the actor thread.
The actor object itself is just some data that lives on the heap. Both the original thread and the thread you create in the actor object's initialization are accessing references to the same object on the same heap that all the threads share.
When you do a method call in the actor thread, you are effectively fetching a reference to the method implementation from the class method table and running it. The calls do happen in different thread contexts, but the method implementation itself is shared via the heap too.
Bottom line: this is not magic, it's just a use of shared memory between threads.
Upvotes: 2