e81 cse 532s: advanced multi-paradigm software development venkita subramonian, christopher gill,...

Post on 02-Jan-2016

217 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

E81 CSE 532S: Advanced Multi-Paradigm Software Development

Venkita Subramonian, Christopher Gill, Guandong Wang, Zhenning Hu, Zhenghui Xie

Department of Computer Science and EngineeringWashington University, St. Louis

cdgill@cse.wustl.edu

Reactor Pattern

Motivating Example: A Logging Server

From http://www.cs.wustl.edu/~schmidt/patterns-ace.html

Evolving to Concurrent Event Handling

Logging Server

CONNECT

Client1

Port:27098

Client2

Port:26545

CONNECT

Goal: process multiple service

requests concurrently

Port:30000 listen

Port:24467 accept

Port:25667 accept

Where We’re Startingmain(){ bind listening port; listen

for (;;) { new_conn_socket = accept ();

run(handler(new_conn_socket)); // write, read

}}

Logging Server: Threaded Approachmain(){ bind listening port; listen

for (;;) { new_conn_socket = accept ();

// fork a process or spawn a thread for handler

thread.run(handler(new_conn_socket)); }}

Problems with Threaded Approach

• Multi-threading may increase code complexity• Multi-threading/processing adds overhead

– Context switching (especially among processes)– Synchronization for shared data, other resources

• What if we could make 1 thread responsive?– Better resource utilization by aligning threading

strategy to # of available resources (like CPUs)– Also, multi-threading may not be available in all OS

platforms (e.g., embedded ones)

Alternative: Event Driven Server

handle_connection_request

handle_data_read

Connection Acceptor

Data Reader

Event Handlers

• Inversion of control• Hollywood principle –

Don’t call us, we’ll call you (“there is no main”)

(reusable: e.g., from ACE) Event Dispatching Logic

(pluggable: you write for your application)Event Handling Logic

Reactor Pattern (Dispatching Logic)

• An architectural pattern– Context: event-driven application– Concurrent reception of multiple

service requests, but serial processing of each one

• Dispatch service requests – Calls the appropriate event handler

• Also known as– Dispatcher, Notifier, Selector (see Java

NIO)

Design Forces

• Enhance scalability• Maximize throughput• Minimize latency • Reduce effort that is needed to

integrate new services into server

Solution – Separation of ConcernsApplication

Reactor

Event HandlersEvent sources

De-multiplexing &Dispatching

Application logic

Synchronous wait

Serial Dispatching

Reactor Pattern Structure

From http://www.cs.wustl.edu/~schmidt/patterns-ace.html

a.k.a“the reactor”

Synchronous vs. Reactive Read

read()

Clients Server

select()

Clients Server

read()

data data

HandleSetHandleSet

Serial Event Dispatching

select()Clients

Application

Event Handlers

read()

read()

Reactor

handle_*()

HandleSet

Interactions among Participants

Main ProgramConcrete Event

HandlerReactor

SynchronousEvent

Demultiplexer

register_handler(handler, event_types)

get_handle()

handle_events()select()

event

handle_event()

Implementation

• De-multiplexer/dispatcher infrastructure – Anonymous de-multiplexing of events to

handlers – Assumes specific event handler hook

methods

• Application – Defines concrete event handlers– Handlers perform service-specific

processing (“Service Handlers”)

Event Handler Interface

• Determine type of dispatching target– Objects vs. functions– Can have pointers to either– Command pattern can unify these– E.g., handle_event ()

• Event handling dispatch interface strategy– Single-method dispatch

• handle_event (handle, event_type)

– Multi-method dispatch• handle_input (handle)• handle_output (handle)• handle_timeout (handle)

Note: singular, not plural

Reactor Interface

• Handler registration/deregistration– E.g., register_handler() deregister_handler()

• Consider visitor, observer patterns• Event loop

– E.g., handle_events()

Note: plural, not singular

Reactor Implementation

• Reactor implementation hierarchy– Abstract base class or template concept– Concrete platform-specific implementations

• Synchronous event de-multiplexing mechanism– E.g., WaitForMultipleObjects() on Win32– E.g., select() or poll() on UNIX platforms

• Implement a dispatch table• Complete concrete reactor

implementation– Hook dispatch table into de-mux mechanism

Multiple Reactors

• A single reactor instance will work in most cases– Sometimes desirable, e.g., for handler serialization – Can use Singleton (e.g., ACE_Reactor::instance())

• Limits on number of OS handles may restrict this– Total available (rarely an issue in a general-purpose

OS)– Max a single thread can wait for

• E.g., 64 in some Win32 platforms

– May need multiple reactors, each with its own thread– Note that handlers are not serialized across Reactor

instances – treat remote/concurrent reactors similarly

Concrete Event Handlers

• Implement base interface / model concept

• Determine policies for handler state– Stateless, stateful, or a combination

• ACTs (cookies) can help offload some of the state

• I.e., can keep state outside the handler objects, but index into a data structure, etc. using the ACT

• Implement event handler functionality– I.e., add application logic to handler

methods

Example Resolved: Part 1

Steps performed when a client connects to the logging server

From http://www.cs.wustl.edu/~schmidt/patterns-ace.html

a.k.a. “the reactor”

Example Resolved: Part 2

Steps performed by reactive logging server to for each record

From http://www.cs.wustl.edu/~schmidt/patterns-ace.html

a.k.a. “the reactor”

Variant: Integrated De-multiplexing of Timer and I/O Events

• Timer-based and I/O-based events in same reactor

• Extend reactors and event handlers– Register concrete event handlers for some time trigger

• Relative vs. absolute time triggers• Periodic vs. one time invocation

– Reactor calls handler’s handle_timeout() method• Can use same handler for time and event dispatching• E.g., an alert watchdog timer for some logging handler

– Various timer strategies• E.g., select/WFMO timeout• E.g., hardware timer interrupt• E.g., polling Pentium tick counter• Key trade-offs between portability, overhead and

responsiveness

Variant: Re-entrant Reactors

• Event handlers re-invoke reactor->handle_events()

– Result: nested event handlers – E.g., CORBA AMI nested work_pending()

• Reactor implementation must be re-entrant– Copy the handle set state onto the run-time stack– Any changes to handle set are local to that nesting

level of the reactor– Use thread stack frame to record reactor’s logical

“stack frame”

Variant: Thread-Safe Reactor

• Synchronized reactor– Lock to synchronize access to the reactor’s

internal state• Multiple threads could register/remove event

handlers

– Preventing self-deadlock • An event handler could register/remove other

event handlers or itself

– Explicitly notifying a waiting event loop thread• Notify the reactor of a change so that the wait

handle-set could be updated

Variant: Concurrent Event Handlers

• Event handlers with their own threads– In addition to event loop thread(s)

• Related concurrency patterns– the Active Object – the Leader/Followers– the Half-Sync/Half-Async

Variant: Concurrent Event De-multiplexer

• Event de-multiplexer concurrent in multiple threads

• E.g., WaitForMultipleObjects()• Benefits

– Can improve throughput significantly for some applications

• Drawbacks– Need a thread-safe event de-multiplexer wrapper

façade– Less portable (fewer platforms support this)– Implementation can become more complex

top related