SoFunction
Updated on 2025-03-08

In-depth analysis of ACE reactor mode

Reactor: Architectural pattern for event separation and dispatch
Generally, there are two ways to work for a file or device specified by a file descriptor: blocking and non-blocking. The so-called blocking method means that when trying to read and write the file descriptor, if there is nothing to read at that time or it is temporarily unwritable, the program will enter a waiting state until something to read or write. For non-blocking states, if nothing can be read or cannot be written, the read and write function returns immediately without waiting.

In the example of Tcp communication mentioned in the previous chapter, the blocking working method is adopted: when receiving tcp data, if there is no data to be read in the remote end, it will be blocked until the required data is read. This method of transmission is similar to the call of traditional passive methods. It is very intuitive, simple and effective, but there is also an efficiency problem. If you are developing a server program facing thousands of connections, and communicate with each client in a blocking manner, if there is a very time-consuming read and write operation, other client communications will not be responsive and are very inefficient.
A common practice is:Each time a Socket connection is established, a new thread is created to communicate separately to the Socket (communicate in a blocking manner). This method has a high response speed and is simple to control. It is very effective when there are fewer connections. However, if a thread is generated for each connection, it is undoubtedly a waste of system resources. If there are many connections, there will be insufficient resources.
Another more efficient approach is:The server saves a list of Socket connections and polls the list. If you find that data is readable on a Socket port (read-read-read-read-read-read-read-read-read-read-read-operation of the socket connection; if you find that data is writeable on a Socket port (write-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read-read This will make full use of server resources and greatly improve efficiency.
In Socket programming, this method can be implemented through select and other related APIs. However, it is more troublesome to control directly with these APIs, and it is also difficult to control and transplant. This development process can be simplified through the Reactor mode in ACE.

The reactor essentially provides a more advanced set of programming abstractions, simplifying the design and implementation of event-driven distributed applications. In addition, the reactor integrates several different kinds of events into an easy-to-use API. In particular, the reactor uniformly processes timer-based events, signal events, I/O port-based monitoring events, and user-defined notifications.

The reactor in the ACE works in conjunction with several internal and external components. The basic concept is that the reactor framework detects the occurrence of events (by listening on the OS event separation interface) and issues a "callback" to the methods in the pre-registered event handler object. This method is implemented by the application developer, which contains specific code for the application to handle this event.
Using ACE's reactor,Just take a few steps:
Create an event handler to handle an event of interest.
Register on the reactor and inform him that he is interested in handling an event, while passing the pointer of the event handler he wants to use to handle the event to the reactor.
The reactor frame will then automatically:
Maintain some tables internally, associating different event types with event handler objects.
When an event registered by the user occurs, the reactor issues a callback to the corresponding method in the processor.
The reactor mode is implemented in ACE as the ACE_Reactor class, which provides a functional interface to the reactor framework.
As mentioned above, the reactor uses the event processor object as a service provider. The relevant callback method for recording a specific event of an event processor inside the reactor. When these events occur, the reactor creates an association between such events and the corresponding event handler.
Event handler
An event processor is an object in the object list that needs to be polled by polling the event. For example, in the above example, it is a connected client, and each client can be regarded as an event processor.
Callback Event
It is the event supported by the reactor, such as Socket read and write ready. Take the example above for example. If a client (event processor) registers a read-ready event in the reactor, when the client sends a message to the server, the client's data readable callback function will be triggered.
In the reactor framework, all application-specific event handlers must be derived from the abstract interface class of ACE_Event_Handler. The relevant callback method can be implemented by overloading the corresponding "handle_" method.
There are basically three steps to use ACE_Reactor:
Create a subclass of ACE_Event_Handler and implement the appropriate "handle_" method there to handle the event type you want this event handler to serve.
By calling the reactor objectregister_handler(), register your event processor to the reactor.
When an event occurs, the reactor will automatically call back the appropriate handle_" method of the corresponding event handler object.