Event Handling Patterns

This chapter presents four patterns that describe how to initiate, receive, demultiplex, dispatch, and process events in networked systems: Reactor, Proactor, Asynchronous Completion Token, and Acceptor-Connector.

Event-driven architectures are becoming pervasive in networked software applications. The four patterns in this chapter help to simplify the development of flexible and efficient event-driven applications. The first pattern can be applied to develop synchronous service providers:

It is the responsibility of a designated component, called reactor, not an application, to wait for indication events synchronously, demultiplex them to associated event handlers that are responsible for processing these events, and then dispatch the appropriate hook method on the event handler. In particular, a reactor dispatches event handlers that react to the occurrence of a specific event. Application developers are therefore only responsible for implementing concrete event handlers and can reuse the reactor's demultiplexing and dispatching mechanisms.

Although the Reactor pattern is relatively straightforward to program and use, it has several constraints that can limit its applicability. In particular it does not scale to support a large number of simultaneous clients and/or long-duration client requests well, because it serializes all event handler processing at the event demultiplexing layer. The second pattern in this chapter can help alleviate these limitations for event-driven applications that run on platforms that support asynchronous I/O efficiently:

In the Proactor pattern, application components--represented by clients and completion handlers--are proactive entities. Unlike the Reactor pattern, which waits passively for indication events to arrive and then reacts, clients and completion handlers in the Proactor pattern instigate the control and data flow within an application by initiating one or more asynchronous operation requests proactively on an asynchronous operation processor.

When these asynchronous operations complete, the asynchronous operation processor and and a designated proactor component collaborate to demultiplex the resulting completion events to their associated completion handlers and dispatch these handlers' hook methods. After processing a completion event, a completion handler may initiate new asynchronous operation requests proactively.

The remaining two design patterns in this chapter can be applied in conjunction with the first two architectural patterns to cover a broader range of event-driven application concerns.

The next pattern is particularly useful for optimizing the demultiplexing tasks of a Proactor implementation, because it addresses an important aspect of asynchronous application design:

The final pattern in this chapter is often used in conjunction with the Reactor pattern for networking applications:

All four patterns presented in this chapter are often applied in conjunction with the Concurrency patterns presented in Chapter 5. Other patterns in the literature that address event handling include Event Notification [Rie96], Observer [GoF95], and Publisher-Subscriber [POSA1].