This is an example of proactor usage on APG. The trace information is removed and a slight modification is made:
Code:
#include <ace/Os_main.h>
#include <ace/Asynch_Acceptor.h>
#include <ace/Proactor.h>
#define LISTEN_PORT 5222
class HA_Proactive_Service : public ACE_Service_Handler
{
public:
~HA_Proactive_Service ()
{
if (this->handle () != ACE_INVALID_HANDLE)
ACE_OS::closesocket (this->handle ());
}
virtual void open (ACE_HANDLE h, ACE_Message_Block&)
{
this->handle (h);
if (this->reader_.open (*this) != 0 || this->writer_.open (*this) != 0 )
{
delete this;
return;
}
ACE_Message_Block *mb;
ACE_NEW_NORETURN (mb, ACE_Message_Block (1024));
if (this->reader_.read (*mb, mb->space ()) != 0)
{
mb->release ();
delete this;
return;
}
}
virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
ACE_Message_Block &mb = result.message_block ();
if (!result.success () || result.bytes_transferred () == 0)
{
mb.release ();
delete this;
}
else
{
ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Received Data : %c/n"), *mb.rd_ptr()));
mb.release();
ACE_Message_Block *new_mb;
ACE_NEW_NORETURN (new_mb, ACE_Message_Block (1024));
this->reader_.read (*new_mb, new_mb->space ());
}
}
virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result)
{ result.message_block ().release (); }
private:
ACE_Asynch_Read_Stream reader_;
ACE_Asynch_Write_Stream writer_;
};
class HA_Proactive_Acceptor : public ACE_Asynch_Acceptor<HA_Proactive_Service>
{
};
int ACE_TMAIN (int, ACE_TCHAR *[])
{
ACE_INET_Addr listen_addr( LISTEN_PORT );
HA_Proactive_Acceptor aio_acceptor;
if (0 != aio_acceptor.open (listen_addr, 0, 0, 5, 1, 0, 0))
ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p/n"), ACE_TEXT ("acceptor open")), 1);
ACE_Proactor::instance ()->proactor_run_event_loop ();
return 0;
}
The program listens on port 5222. For each established connection, the server prints all received data to the console. This is the function implemented by the entire program.
However, this program has a big problem: there is no way to end it normally. After running this program, you can only force the process to end, because the program does not provide a way to exit from the proactor event loop.
It is necessary to enable the program to exit normally. For example, if the program cannot exit normally during memory leak detection, it will be difficult to detect memory leakage.
In order to properly close the program, you need to slightly modify the above program implementation.
This program will have two threads running, one is the proactor event loop thread, and the other is the control thread. In the control thread, you must be able to close the proactor thread and then exit the program cleanly.
Thanks to the powerful ace encapsulation, the changes are not significant:
Code:
class ProactorThread : public ACE_Task_Base
{
public:
int open()
{
return this->activate();
}
int close()
{
ACE_Proactor::instance()->proactor_end_event_loop();
this->wait();
return 0;
}
virtual int svc()
{
ACE_INET_Addr listen_addr( LISTEN_PORT );
HA_Proactive_Acceptor aio_acceptor;
if (0 != aio_acceptor.open (listen_addr, 0, 0, 5, 1, 0, 0))
ACE_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("%p/n"), ACE_TEXT ("acceptor open")), 1);
ACE_Proactor::instance ()->proactor_run_event_loop ();
ACE_DEBUG ((LM_DEBUG, ACE_TEXT("Thread ended/n")));
return 0;
}
};
int ACE_TMAIN (int, ACE_TCHAR *[])
{
ProactorThread thread;
thread.open();
int x;
std::cin >> x;
thread.close();
return 0;
}
Only a new class is added to encapsulate the proactor event loop thread, and the main function of the program is modified. This program will first create a proactor event loop thread, and then the main thread waits for the user to enter any number and ends the proactor thread. After the proactor thread Exits normally, the main thread exits.
Note that there are two key points:
1. After proactor_end_event_loop () is executed, the proactor thread exits from proactor_run_event_loop (). Therefore, the following code is executed to print the "thread ended" information.
2. the main thread must use wait () to wait until the proactor thread ends normally before exiting. Otherwise, if the main thread exits, the proactor thread still has some resources to be released, in this case, resources are incorrectly released.