這是APG上關於Proactor使用的例子,去掉了trace資訊,做了一點小修改:
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;
}
程式在5222連接埠上監聽,對於每個已建立的串連,伺服器將所有收到的資料列印到控制台上。這就是整個程式所實現的功能。
但是這個程式存在一個很大的問題:沒有辦法正常結束。當運行這個程式後,只能強制結束這個進程,因為程式沒有提供從proactor事件迴圈中退出來的方法。
讓程式能夠正常退出是很有必要的,比如在進行記憶體流失的檢測時,如果程式沒有辦法正常退出,那麼記憶體流失的檢測工作將很難進行。
為了實現能夠正常關閉程式的目的,需要稍微修改一下上面的程式實現。
這次程式將會有兩個線程在運行,一個是Proactor事件迴圈線程,另一個則為控制線程。在控制線程中,要能夠關閉Proactor線程,然後將程式乾淨地退出。
得益於ACE強大的封裝,所做的改動並不大:
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;
}
僅僅只是添加了一個新的類,用於封裝Proactor事件迴圈線程,另外修改了程式的主函數。這次程式將首先建立一個Proactor事件迴圈線程,然後主線程等待使用者輸入任意數後結束Proactor線程,在Proactor線程正常退出後主線程退出。
注意這裡有兩個要點:
1.當執行proactor_end_event_loop()之後,Proactor線程是從proactor_run_event_loop()處退出,所以會接著執行下面的代碼,列印出” Thread ended”資訊。
2.主線程必須使用wait()等待Proactor線程正常結束後再退出,否則如果主線程退出後,Proactor線程仍有一些資源釋放工作未完成,那麼就會存在資源未正確釋放的問題。