Active Object 1 Intent 2 Also Known As 3 Example
Total Page:16
File Type:pdf, Size:1020Kb
Active Object an Object Behavioral Pattern for Concurrent Programming R. Greg Lavender Douglas C. Schmidt [email protected] [email protected] ISODE Consortium Inc. Department of Computer Science Austin, TX Washington University, St. Louis An earlier version of this paper appeared in a chapter in erating components in a distributed system and allows them the book “Pattern Languages of Program Design 2” ISBN to interact without having direct dependencies among each 0-201-89527-7, edited by John Vlissides, Jim Coplien, and other [2]. The Gateway shown in Figure 1 routes messages Norm Kerth published by Addison-Wesley, 1996. from one or more supplier processes to one or more con- sumer processes in a distributed system [3]. Abstract This paper describes the Active Object pattern, which decou- Consumer ples method execution from method invocation in order to Supplier Routing Handler simplify synchronized access to an object that resides in its Handler Table Message own thread of control. The Active Object pattern allows one Queue or more independent threads of execution to interleave their 2: find_route (msg) access to data modeled as a single object. A broad class of 3: put (msg) Consumer producer/consumer and reader/writer applications are well- Handler suited to this model of concurrency. This pattern is com- Supplier Message Handler monly used in distributed systems requiring multi-threaded Queue servers. In addition, client applications, such as window- 1: recv (msg) ing systems and network browsers, employ active objects to OUTGOING simplify concurrent, asynchronous network operations. OUTGOING MESSAGES GATEWAY MESSAGES INCOMING INCOMING 1Intent MESSAGES MESSAGES The Active Object design pattern decouples method execu- tion from method invocation to simplify synchronized access CONSUMER CONSUMER to an object that resides in its own thread of control. Meth- SUPPLIER SUPPLIER ods invoked by clients on an object are not executed directly Figure 1: Communication Gateway in the thread of the caller. Instead, they are transformed by a Proxy into Method Requests and stored in an Activation In our example, the Gateway, suppliers, and consumers Queue. When synchronization constraints are met, Method communicate over TCP connections. Internally, the Gate- Requests are executed by a Scheduler running in its own way software contains a set of Supplier and Consumer thread of control. Results can be returned to the client via Handlers, which act as local proxies [2, 4] for re- a Future. mote suppliers and consumers, respectively. Supplier Handlers receive messages from remote suppliers. They 2 Also Known As inspect address fields in the messages and use a routing ta- ble to find the appropriate Consumer Handlers asso- Concurrent Object and Actor ciated with the one or more consumers. The Consumer Handler(s) then deliver the message to remote con- sumer(s). 3 Example The suppliers, consumers, and Gateway communicate us- ing TCP, which is a connection-oriented protocol [5]. There- To illustrate the Active Object pattern, consider the design of fore, Consumer Handlers in the Gateway software may a communication Gateway [1]. A Gateway decouples coop- encounter flow control from the TCP transport layer when 1 they try to send data to a consumer. TCP uses flow control to a single thread of control, however, performance bottlenecks ensure that fast suppliers or Gateways do not produce data cannot be alleviated transparently by running the Gateway more rapidly than slow consumers or congested networks on a multi-processor. can buffer and process the data. To improve end-to-end quality of service (QoS) for all suppliers and consumers, a Consumer Handler must not 6 Solution block the entire Gateway waiting for flow control to abate over any one connection to a consumer. In addition, the For each object that requires concurrent execution, decou- Gateway must be able to scale up efficiently as the number ple method invocation on the object from method execution. of suppliers and consumers increase. An effective way to A Proxy [4, 2] represents the interface of the object and a prevent blocking and to improve performance is to introduce Servant [6] provides its implementation. Both the Proxy concurrency into the design of the Gateway. Concurrent ap- and the Servant run in separate threads so that method in- vocation and method execution can run concurrency. At plications allow the thread of control of an object O that ex- ecutes a method to be decoupled from the thread of control run-time, the Proxy transforms the client’s method invoca- tion into a Method Request, which is stored in an Activation of objects that invoke methods on O . Queue by a Scheduler. The Scheduler runs continuously in its own thread, dequeueing Method Request from the Activa- 4 Context tion Queue and dispatching them on the Servant that imple- ments the object. Clients can obtain the results of a method’s Applications that use concurrency to communicate between execution via the Future returned by the Proxy. clients and servers running in separate threads of control. 7 Structure 5Problem The structure of the Active Object pattern is illustrated in the Many applications benefit from applying concurrency to im- following Booch class diagram: prove their QoS, e.g., by enabling an application to handle multiple client requests in parallel. Instead of using single- loop { threaded passive objects, which execute their methods in the m = act_que.dequeue() thread of control of the client that invoked the method, con- Proxy m.call() current objects reside in their own thread of control. How- } Future m1() 1: enqueue(new M1) ever, if objects run concurrently we must synchronize ac- Future m2() cess to their methods if these objects are shared by multiple Future m3() 3: dispatch() Activation clients. Three forces arise: Scheduler Queue enqueue() dispatch() dequeue() 1. Methods invoked on the object should not block VISIBLE enqueue() 1 1 in order to prevent degrading the QoS of other meth- TO CLIENTS 1 2: enqueue(M1) ods: For instance, if a Consumer Handler object in 1 1 M1 our Gateway example is blocked due to flow control on Servant Method n its TCP connection, Supplier Handler objects should INVISIBLE m1() M2 TO Request still be able to pass new messages to this Consumer CLIENTS m2() 111 1 Handler. Likewise, if other Consumer Handlersare m3() call() M3 not flow controlled, they should be able to send messages to 4: m1() their consumers independently of any blocked Consumer Handlers. There are six key participants in the Active Object pattern: 2. Synchronized access to shared data should be sim- Proxy ple: Applications like the Gateway example are often hard to program if developers must explicitly use low-level syn- A Proxy [2, 4] provides an interface to publically ac- chronization mechanisms, such as acquiring and releasing cessible methods of an Active Object. This interface al- locks. In general, methods that are subject to synchroniza- lows clients to invoke methods. When a client invokes a tion constraints should be serialized transparently when an method defined by the Proxy, this triggers the construc- object is accessed by multiple client threads. tion and queueing of a Method Request. 3. Applications should be designed to transpar- Method Request ently leverage the parallelism available on a hard- ware/software platform: In our Gateway example, mes- A Method Request is constructed by a Proxy for any sages destined for different Consumer Handlers should method call that requires synchronized access to an Ac- be sent in parallel by a Gateway. If the entire Gateway runs in tive Object. Each Method Request maintains context 2 information, such as method parameters and method Client Scheduler M1 code, necessary to (1) execute a method invocation and Activation (2) to return any results of that invocation back through Proxy Queue Servant m1() the Future. In addition, Method Requests may con- INVOKE CREATE METHOD enqueue(new M1) tain predicates that can be used to determine when the REQUEST Method Request’s synchronization constraints are met. RETURN FUTURE future() CONSTRUCTION METHOD OBJECT / INSERT INTO enqueue(M1) ACTIVATION QUEUE DEQUEUE NEXT dequeue(M1) Activation Queue METHOD REQUEST dispatch(M1) EXECUTION SCHEDULING EXECUTE call() m1() An Activation Queue maintains a priority queue of RETURN RESULT reply_to_future() pending method invocations, which are represented as Method Request created by the Proxy. COMPLETION 1. Method Request construction and scheduling: In this Scheduler phase, the client invokes a method defined by the Proxy. This triggers the creation of a Method Request, which maintains the argument bindings to the method, as well as any other A Scheduler runs in its own thread managing an Acti- bindings required to execute the method and return its re- vation Queue of Method Requests that are pending ex- sults. The Proxy then passes the Method Request to the ecution. The Scheduler decides which Method Request Scheduler, which enqueues it on the Activation Queue. If to dequeue and execute on the Servant that implements the method is defined as a twoway [6], a binding to a Future the method. This can be based on various criteria, such is returned to the caller of the method. If a method is de- as ordering, e.g., the order in which Method Requests fined as a oneway, i.e., it has no return values, no Future is are invoked by clients, and synchronization constraints, returned. e.g., mutual exclusion, which are evaluated by using Method Request predicates. 2. Method execution: In this phase, the Scheduler runs continuously in a different thread than any of its clients. Within this thread, the Scheduler monitors the Activation Queue and determines which Method Request(s) have be- Servant come runnable, e.g., when their synchronization constraints are met. When a Method Request becomes runnable, the Scheduler dequeues it, binds it to the Servant, and dispatches A Servant defines the behavior and state that is being appropriate method on the Servant.