Changes in / [6d18ddb:df27752]


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/colby_parsons_MMAth/text/actors.tex

    r6d18ddb rdf27752  
    77% C_TODO: add citations throughout chapter
    88Actors are an indirect concurrent feature that abstracts threading away from a programmer, and instead provides \gls{actor}s and messages as building blocks for concurrency, where message passing means there is no shared data to protect, making actors amenable in a distributed environment.
    9 Actors are another message passing concurrency feature, similar to channels but with more abstraction, and are in the realm of \gls{impl_concurrency}, where programmers write concurrent code without dealing with explicit thread creation or interaction.
     9Actors are another message passing concurrency feature, similar to channels but with more abstraction, and are in the realm of \gls{impl_concurrency}, where programmers write concurrent code without dealing with explicit thread create or interaction.
    1010The study of actors can be broken into two concepts, the \gls{actor_model}, which describes the model of computation and the \gls{actor_system}, which refers to the implementation of the model.
    1111Before discussing \CFA's actor system in detail, it is important to first describe the actor model, and the classic approach to implementing an actor system.
     
    244244Because a C program manages message lifetime, messages cannot be copied for each send, otherwise who manages the copies.
    245245Therefore, it up to the actor program to manage message life-time across receives.
    246 However, for a message to appear on multiple message queues, it needs an arbitrary number of associated destination behaviours.
     246However, for a message to appear on multiple message queues, it needs an arbitrary number of link fields.
    247247Hence, there is the concept of an envelop, which is dynamically allocated on each send, that wraps a message with any extra implementation fields needed to persist between send and receive.
    248248Managing the envelop is straightforward because it is created at the send and deleted after the receive, \ie there is 1:1 relationship for an envelop and a many to one relationship for a message.
     
    281281All actors must be created \emph{after} calling @start_actor_system@ so the executor can keep track of the number of actors that have entered the system but not yet terminated.
    282282
     283% All message sends are done using the vertical-bar operator, @?|?@, similar to the syntax of \CC's stream output.
     284% \begin{cfa}
     285% allocation ?|?( my_actor & receiver, my_msg & msg )
     286% \end{cfa}
     287% Notice this signature is the same as the @receive@ routine, which is no coincidence.
     288% The \CFA compiler generates a @?|?@ routine definition and forward declaration for each @receive@ routine that has the appropriate signature.
     289% The generated routine packages the message and actor in an \hyperref[s:envelope]{envelope} and adds it to the executor's queues via an executor routine.
     290% As part of packaging the envelope, the @?|?@ routine sets a routine pointer in the envelope to point to the appropriate receive routine for given actor and message types.
     291
    283292\subsection{Actor Send}\label{s:ActorSend}
    284293All message sends are done using the vertical-bar (bit-or) operator, @?|?@, similar to the syntax of the \CFA stream I/O.
    285 Hence, programmers must write a matching @?|?@ routine for each @receive@ routine, which is awkward and generates a maintenance problem That must be solved.
    286 The currently supported approach to creating a generic @?|?@ routine requires users to create specific routines for their actor and message types that access the base type.
    287 Since these routines are not complex, they can be generated using macros that the user can add following their message and actor types.
    288 This works, but is not much better than asking users to write the @?|?@ routine themselves.
    289 
    290294As stated, \CFA does not have named inheritance with RTTI.
    291295\CFA does have a preliminary form of virtual routines, but it is not mature enough for use in this work.
    292 Virtuals would provide a clean mechanism to write a single generic @?|?@ routine taking a base actor and message type, and then dynamically selecting the @receive@ routine from the actor argument.
    293 Note, virtuals are not needed for the send; Plan-9 inheritance is sufficient because only the inherited fields are needed during the message send (only upcasting is needed).
    294 
    295 Therefore, a template-like approach was chosen, where the compiler generates a matching @?|?@ routine for each @receive@ routine it finds with the correct actor/message type-signature.
    296 This approach requires no annotation or additional code to be written by users, thus it resolves the maintenance problem.
     296Therefore, there is no mechanism to write a generic @?|?@ routine taking a base actor and message type, and then dynamically selecting the @receive@ routine from the actor argument.
     297(For messages, the Plan-9 inheritance is sufficient because only the inherited fields are needed during the message send.)
     298Hence, programmers must write a matching @?|?@ routine for each @receive@ routine, which is awkward and generates a maintenance problem.
     299Therefore, I chose a template-like approach, where the compiler generates a matching @?|?@ routine for each @receive@ routine it finds with the correct actor/message type-signature.
    297300(When the \CFA virtual routines mature, it should be possible to seamlessly transition to it from the template approach.)
     301
     302% Funneling all message sends through a single @allocation ?|?(actor &, message &)@ routine is not feasible since the type of the actor and message would be erased, making it impossible to acquire a pointer to the correct @receive@.
     303% As such a @?|?@ routine per @receive@ provides type information needed to write the correct "address" on the envelope.
    298304
    299305Figure~\ref{f:send_gen} shows the generated send routine for the @int_msg@ receive in Figure~\ref{f:CFAActor}.
     
    323329\end{figure}
    324330
    325 \subsection{Actor Termination}\label{s:ActorTerm}
    326 As discussed in Section~\ref{s:ActorSend}, during a message send, the derived type of the actor and message is erased, and then recovered later by calling the receive routine.
    327 After the receive routine is done, the executor must clean up the actor and message according to their allocation status.
    328 If the allocation status is @Delete@ or @Destroy@, the appropriate destructor must be called by the executor.
    329 This poses a problem; the type of the actor or message is not available to the executor, but it needs to call the right destructor!
    330 This requires down-casting from the base type to derived type, which requires a virtual system.
    331 Thus, a rudimentary destructor-only virtual system was added to \CFA as part of this work.
    332 This virtual system is used via Plan-9 inheritance of the @virtual_dtor@ type.
    333 The @virtual_dtor@ type maintains a pointer to the start of the object, and a pointer to the correct destructor.
    334 When a type inherits the @virtual_dtor@ type, the compiler adds code to its destructor to make sure that whenever any destructor along inheritance tree is called, the destructor call is intercepted, and restarts at the appropriate destructor for that object.
    335 
    336 \begin{figure}
    337 \begin{cfa}
    338 struct base_type { inline virtual_dtor; };
    339 struct intermediate_type { inline base_type; };
    340 struct derived_type { inline intermediate_type; };
    341 
    342 int main() {
    343     derived_type d1, d2, d3;
    344     intermediate_type & i = d2;
    345     base_type & b = d3;
    346     ^d1{}; ^i{}; ^b{}; // all of these will call the destructors in the correct order
    347 }
    348 
    349 \end{cfa}
    350 \caption{\CFA Virtual Destructor}
    351 \label{f:VirtDtor}
    352 \end{figure}
    353 
    354 This virtual destructor system was built for this work, but is general and can be used in any type in \CFA.
    355 Actors and messages opt into this system by inheriting the @virtual_dtor@ type, which allows the executor to call the right destructor without knowing the derived actor or message type.
    356 
    357331Figure~\ref{f:ConvenienceMessages} shows three builtin convenience messages and receive routines used to terminate actors, depending on how an actor is allocated: @Delete@, @Destroy@ or @Finished@.
    358332For example, in Figure~\ref{f:CFAActor}, the builtin @finished_msg@ message and receive are used to terminate the actor because the actor is allocated on the stack, so no deallocation actions are performed by the executor.
     
    437411The next time 19 messages are enqueued, the array size is doubled to 36!
    438412To avoid this issue, a second check is added.
     413% Each copy queue starts tracking the utilization of its array size.
    439414Reclamation only occurs if less than half of the array is utilized.
    440415This check achieves a lower total storage and overall memory utilization compared to the non-reclamation copy queues.
     
    650625
    651626\subsection{Stealing Guarantees}
     627
     628% C_TODO insert graphs for each proof
    652629Given that the stealing operation can potentially fail, it is important to discuss the guarantees provided by the stealing implementation.
    653630Given a set of $N$ swaps a set of connected directed graphs can be constructed where each vertex is a queue and each edge is a swap directed from a thief queue to a victim queue.
     
    791768Since the @Finished@ allocation status is unused for messages, it is used internally to detect if a message has been sent.
    792769Deallocating a message without sending it could indicate to a user that they are touching freed memory later, or it could point out extra allocations that could be removed.
    793 \item Detection of messages sent but not received
    794 As discussed in Section~\ref{s:executor}, once all actors have terminated shutdown is communicated to executor threads via a status flag. Upon termination the executor threads check their queues to see if any contain messages. If they do, an error is reported. Messages being sent but not received means that their allocation action did not occur and their payload was not delivered. Missing the allocation action can lead to memory leaks and missed payloads can cause unpredictable behaviour. Detecting this can indicate a race or logic error in the user's code.
    795770\end{itemize}
    796771
Note: See TracChangeset for help on using the changeset viewer.