Reactor
Reactor Also known as Problem Solution Structure Dynamic Behavior Example Pros and Cons Pros Cons What’s Next? Event-driven applications, such as GUIs or servers, often apply the architecture pattern Reactor. A Reactor can accept multiple requests simultaneously and distribute them to different handlers. The Reactor Pattern is an event-driven framework to concurrently demultiplex and dispatch service requests to various service providers. The requests are processed synchronously. Reactor Also known as Dispatcher Notifier Problem A server should answer several client requests simultaneously be performant, stable, and scalable be extendable to support new or improved services The application should be hidden from multi-threading and synchronization challenges Solution Each supported service is encapsulated in a handler The handlers are registered within the Reactor The Reactor uses an event demultiplexer to wait synchronously on all incoming events When the Reactor is notified, it dispatches the service request to the specific handler Structure Handles The handles identify different event sources, such as network connections, open files, or GUI events. The event source generates events such as connect, read, or write queued on the associated handle. Synchronous event demultiplexer The synchronous event demultiplexer waits for one or more indication events and blocks until the associated handle can process the event. The system calls select, poll, epoll, kqueue, or WaitForMultipleObjects enable it to wait for indication events. Event handler The event handler defines the interface for processing the indication events. The event handler defines the supported services of the application. Concrete event handler The concrete event handler implements the interface of the application defined by the event handler. Reactor The Reactor supports an interface to register and deregister the concrete event handler using file descriptors. The Reactor uses a synchronous event demultiplexer to wait for indication events. An indication event can be a reading event, a writing event, or an error event. The Reactor maps the events to their concrete event handler. The Reactor manages the lifetime of the event loop. The Reactor (not the application) waits for the indication events to demultiplex and dispatch the event. The concrete event handlers are registered within the Reactor. The Reactor inverts the flow of control. This inversion of control is often called Hollywood principle. The dynamic behavior of a Reactor is pretty interesting. Dynamic Behavior The following points illustrate the control flow between the Reactor and the event handler. The application registers an event handler for specific events in the Reactor. Each event handler provides its specific handler to the Reactor. The application starts the event loop. The event loop waits for indication events. The event demultiplexer returns to the Reactor when an event source becomes ready. The Reactor dispatches the handles to the corresponding event handler. The event handler processes the event. Let’s study the Reactor in action. This example uses the POCO framework. “The POCO C++ Libraries are powerful cross-platform C++ libraries for building network- and internet-based applications that run on desktop, server, mobile, IoT, and embedded systems.” // reactor.cpp #include #include #include “Poco/Net/SocketReactor.h” #include “Poco/Net/SocketAcceptor.h” #include “Poco/Net/SocketNotification.h” #include “Poco/Net/StreamSocket.h” #include “Poco/Net/ServerSocket.h” #include “Poco/Observer.h” #include “Poco/Thread.h” #include “Poco/Util/ServerApplication.h” using Poco::Observer; using Poco::Thread; using Poco::Net::ReadableNotification; using Poco::Net::ServerSocket; using Poco::Net::ShutdownNotification; using Poco::Net::SocketAcceptor; using Poco::Net::SocketReactor; using Poco::Net::StreamSocket; using Poco::Util::Application; class EchoHandler { public: EchoHandler(const StreamSocket& s, SocketReactor& r): socket(s), reactor(r) { // (11) reactor.addEventHandler(socket, Observer<EchoHandler, ReadableNotification>(*this, &EchoHandler::socketReadable)); } void socketReadable(ReadableNotification*) […]
