diff options
Diffstat (limited to 'examples/Reactor/ReactorEx/README')
-rw-r--r-- | examples/Reactor/ReactorEx/README | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/examples/Reactor/ReactorEx/README b/examples/Reactor/ReactorEx/README new file mode 100644 index 00000000000..1184d09dd68 --- /dev/null +++ b/examples/Reactor/ReactorEx/README @@ -0,0 +1,204 @@ +The ACE_ReactorEx encapsulates the Win32 WaitForMultipleObjects() API +within ACE. The ACE_ReactorEx is similar in spirit to the +ACE_Reactor, except that (1) it is much simpler and (2) it works for +the complete range of Win32 handles (whereas the ACE_Reactor just +works for socket handles. + +Here's the API for the ACE_ReactorEx: + +class ACE_ReactorEx +{ +public: + // = Event loop. + virtual int handle_events (ACE_Time_Value *); + + // = Handler registration management. + virtual int register_handler (ACE_Event_Handler *); + virtual int remove_handler (ACE_Event_Handler *); + + virtual int notify (void); + + // = Timer management + virtual int schedule_timer (), etc. + // ... +}; + +---------------------------------------- + +Here's how you might use it: + +---------------------------------------- + +class My_Thread_Handler : public ACE_Event_Handler +{ +public: + My_Thread_Handler (void) { + // Create a thread that will run + // for a time and then exit. + this->thread_handle_ = + ACE_OS::thr_create (run, ......); + } + + // Called back by the ACE_ReactorEx when the + // event is signaled. + virtual int handle_signal (int) + { + cout << "thread is done" << endl; + } + + virtual ACE_HANDLE get_handle (void) const + { + return this->thread_handle_; + } + +private: + ACE_HANDLE thread_handle_; + + static void *run (void *) { + // Sleep for a while and then exit. + ACE_OS::sleep (100000); + return 0; + } +}; + +---------------------------------------- + +The main program might look something like this: + +---------------------------------------- + +int main (void) +{ + // ... + ACE_ReactorEx dispatcher; + My_Thread_Handler handler; + + // Register the thread handler. + dispatcher.register_handler (&handler); + + // Block until the thread exits and the + // handle_signal() method of the My_Thread_Handler + // is called! + dispatcher.handle_events (); + + // ... +} + +---------------------------------------- + +. test_remove_handler -- + +This application tests the ReactorEx's ability to handle simultaneous +events. If you pass anything on the command-line, then each handler +requests to be removed from the ReactorEx after each event. This has +a funky effect on the order in which handlers are serviced. So, if no +parameters are passed in, the handlers should be serviced 1 through +MAXIMUM_WAIT_OBJECTS. If handlers to request to be removed as signals +occur, they will be serviced 1, MAX, MAX-1, ..., 2. This is because +of a ReactorEx bookkeeping optimization. + +. test_reactorEx.cpp -- + +This test application tests a wide range of events that can be +demultiplexed using various ACE utilities. Events used include ^C +events, reading from STDIN, vanilla Win32 events, thread exits, +ReactorEx notifications, proactive reads, and proactive writes. + +The proactive I/O events are demultiplexed by the ACE_Proactor. The +thread exits, notications, and vanilla Win32 events are demultiplexed +by the ACE_ReactorEx. To enable a single thread to run all these +events, the Proactor is integrated with the ReactorEx. + +The test application prototypes a simple ntalk program. Two instances +of the application connect. Input from either console is displayed on +the others console also. Because of the evils of Win32 STDIN, a +separate thread is used to read from STDIN. To test the Proactor and +ReactorEx, I/O between the remote processes is performed proactively +and interactions between the STDIN thread and the main thread are +performed reactively. + +The following description of the test application is in two parts. +The participants section explains the main components involved in the +application. The collaboration section describes how the partipants +interact in response to the multiple event types which occur. + +The ReactorEx test application has the following participants: + +. ReactorEx -- The ReactorEx demultiplexes Win32 "waitable" events + using WaitForMultipleObjects. + +. Proactor -- The proactor initiates and demultiplexes overlapped I/O + operations. The Proactor registers with the ReactorEx so that a + single-thread can demultiplex all application events. + +. STDIN_Handler -- STDIN_Handler is an Active Object which reads from + STDIN and forwards the input to the Peer_Handler. This runs + in a separate thread to make the test more interesting. However, + STDIN is "waitable", so in general it can be waited on by the ACE + ReactorEx, thanks MicroSlush! + +. Peer_Handler -- The Peer_Handler connects to another instance of + test_reactorEx. It Proactively reads and writes data to the peer. + When the STDIN_Handler gives it messages, it fowards them to the + remote peer. When it receives messages from the remote peer, it + prints the output to the console. + +The collaborations of the participants are as follows: + +. Initialization + + Peer_Handler -- connects to the remote peer. It then begins + proactively reading from the remote connection. Note that it will + be notified by the Proactor when a read completes. It also + registers a new_msg_event with the ReactorEx. Note that when the + new_msg_event is signaled (by the STDIN_Handler), + Peer_Handler::handle_signal will get called. + + STDIN_Handler -- STDIN_Handler registers a signal handler for + SIGINT. This just captures the exception so that the kernel doesn't + kill our process; We want to exit gracefully. It also creates an + Exit_Hook object which registers the STDIN_Handler's thread handle + with the ReactorEx. The Exit_Hook will get called back when the + STDIN_Handler thread exits. After registering these, it blocks + reading from STDIN. + + Proactor -- is registered with the ReactorEx. + + The main thread of control waits in the ReactorEx. + +. STDIN events -- When the STDIN_Handler thread reads from STDIN, it + puts the message on Peer_Handler's message queue and signals the + new_msg_event. It then returns to reading from STDIN. + +. new_msg_events -- The ReactorEx thread wakes up and calls + Peer_Handler::handle_signal. The Peer_Handler then tries to dequeue + a message from its message queue. If it can, the message is + Proactively sent to the remote peer. Note that the Peer_Handler + will be notified with this operation is complete. The Peer_Handler + then falls back into the ReactorEx event loop. + +. Send complete event -- When a proactive send is complete, the + Proactor is notified by the ReactorEx. The Proactor, in turn, + notifies the Peer_Handler. The Peer_Handler then checks for more + messages from the message queue. If there are any, it tries to send + them. If there are not, it returns to the ReactorEx event loop. + This is ok since it is notified via new_msg_event when new message + arrive. + +. Read complete event -- When a proactive read is complete (the + Peer_Handler initiated a proactive read when it connected to the + remote peer), the Proactor is notified by the ReactorEx. The + Proactor, in turn notifies the Peer_Handler. If the read was + successful the Peer_Handler just displays the received msg to the + console and reinvokes a proactive read from the network connection. + If the read failed (i.e. the remote peer exited), the Peer_Handler + sets a flag to end the event loop and returns. This will cause the + application to exit. + +. ^C events -- When the user types ^C at the console, the + STDIN_Handler's signal handler will be called. It does nothing, but + as a result of the signal, the STDIN_Handler thread will exit. + +. STDIN_Handler thread exits -- The Exit_Hook will get called back + from the ReactorEx. Exit_Hook::handle_signal sets a flag to end the + event loop and returns. This will cause the application to exit. |