Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Akka implement the JMM-like happens-before relationship?

In the official Akka doc, they disclaim:

To prevent visibility and reordering problems on actors, Akka guarantees the following two "happens before" rules:

The actor send rule: the send of the message to an actor happens before the receive of that message by the same actor. The actor subsequent processing rule: processing of one message happens before processing of the next message by the same actor.

Please ref the doc for details.

I'm wondering how does Akka achive this. I just went through the source code(latest at this moment), and I thought there should be a Lock before execute Actor.receive, but I didn't find any locks(I think). Finally, I found a comment for ActorCell.invoke:

//Memory consistency is handled by the Mailbox (reading mailbox status then processing messages, then writing mailbox status

Yeah, the Mailbox.status, I guess this is what I'm looking for. I saw they use Unsafe to access/update the status field, but I just couldn't figure out how can this ensure the memory visibility.

like image 905
Evans Y. Avatar asked Apr 06 '13 09:04

Evans Y.


1 Answers

There are two things to consider: passing the message and correctly publishing the actor’s internal state.

The former is achieved by the mailbox’s MessageQueue implementation which will use volatile writes (for the default ConcurrentLinkedQueue) or locks (for a normal LinkedBlockingQueue) to ensure safe publication of the enqueued item. The actor will synchronize-with the sender by reading the same volatile fields (in the first case) or taking the same locks (in the second), hence all writes prior to the message send happen-before anything within the actor when processing that message.

The actor’s internal state is safely stowed away even when it is rescheduled on a different thread by the mailbox status you have found: after processing a batch of messages (defined by the throughput parameter) the mailbox is set to “not scheduled” status, which is a volatile write (actually Unsafe.compareAndSetInt(), which has the same semantics). Before the actor starts processing messages it reads the mailbox status using Unsafe.getIntVolatile, which synchronizes-with the previous write, hence all writes done by the actor during the last batch of messages happen-before all reads during this batch.

You can read more about the semantics of the operations involved here, keeping in mind that the *Volatile methods on sun.misc.Unsafe obey the same rules as those for Atomic*Reference.

like image 92
Roland Kuhn Avatar answered Nov 10 '22 03:11

Roland Kuhn