下面的代码段含有两个方法对象的实现:
例
5-3c//Implementation for the logMsg_MO method object.
//Constructor
logMsg_MO::logMsg_MO(Logger * logger, const char * msg, ACE_Future
&future_result)
:logger_(logger), msg_(msg), future_result_(future_result)
{
ACE_DEBUG((LM_DEBUG, "(%t) logMsg invoked \n"));
}
//Destructor
logMsg_MO::~logMsg_MO()
{
ACE_DEBUG ((LM_DEBUG, "(%t) logMsg object deleted.\n"));
}
//Invoke the logMsg() method
int logMsg_MO::call (void)
{
return this->future_result_.set (
this->logger_->logMsg_i (this->msg_));
}
//Implementation for the name_MO method object.
//Constructor
name_MO::name_MO(Logger * logger, ACE_Future
logger_(logger), future_result_(future_result)
{
ACE_DEBUG((LM_DEBUG, "(%t) name() invoked \n"));
}
//Destructor
name_MO::~name_MO()
{
ACE_DEBUG ((LM_DEBUG, "(%t) name object deleted.\n"));
}
//Invoke the name() method
int name_MO::call (void)
{
return this->future_result_.set (this->logger_->name_i ());
}
这两个方法对象的实现是相当直接的。如上面所解释的,方法对象的构造器负责创建“罩子”(捕捉输入参数和结果)。
call()方法调用实际的方法实现,随后通过使用ACE_Future::set()方法来在期货对象中设置值。下面的代码段显示
Logger主动对象自己的实现。大多数代码都在svc()方法中。程序在这个方法中从启用队列里取出方法对象,并调用它们的call()方法。
例
5-3d//Constructor for the Logger
Logger::Logger()
{
this->name_= new char[sizeof("Worker")];
ACE_OS:strcpy(name_,"Worker");
}
//Destructor
Logger::~Logger(void)
{
delete this->name_;
}
//The open method where the active object is activated
int Logger::open (void *)
{
ACE_DEBUG ((LM_DEBUG, "(%t) Logger %s open\n", this->name_));
return this->activate (THR_NEW_LWP);
}
//Called then the Logger task is destroyed.
int Logger::close (u_long flags = 0)
{
ACE_DEBUG((LM_DEBUG, "Closing Logger \n"));
return 0;
}
//The svc() method is the starting point for the thread created in the
//Logger active object. The thread created will run in an infinite loop
//waiting for method objects to be enqueued on the private activation
//queue. Once a method object is inserted onto the activation queue the
//thread wakes up, dequeues the method object and then invokes the
//call() method on the method object it just dequeued. If there are no
//method objects on the activation queue, the task blocks and falls
//asleep.
int Logger::svc (void)
{
while(1)
{
// Dequeue the next method object (we use an auto pointer in
// case an exception is thrown in the
). auto_ptr
mo (this->activation_queue_.dequeue ());
ACE_DEBUG ((LM_DEBUG, "(%t) calling method object\n"));
// Call it.
if (mo->call () == -1)
break;
// Destructor automatically deletes it.
}
return 0;
}
//////////////////////////////////////////////////////////////
//Methods which are invoked by client and execute asynchronously.
//////////////////////////////////////////////////////////////
//Log this message
ACE_Future
{
ACE_Future
//Create and enqueue method object onto the activation queue
this->activation_queue_.enqueue
(new logMsg_MO(this,msg,resultant_future));
return resultant_future;
}
//Return the name of the Task
ACE_Future
{
ACE_Future
//Create and enqueue onto the activation queue
this->activation_queue_.enqueue
(new name_MO(this, resultant_future));
return resultant_future;
}
///////////////////////////////////////////////////////
//Actual implementation methods for the Logger
///////////////////////////////////////////////////////
u_long Logger::logMsg_i(const char *msg)
{
ACE_DEBUG((LM_DEBUG,"Logged: %s\n",msg));
//Go to sleep for a while to simulate slow I/O device
ACE_OS::sleep(2);
return 10;
}
const char * Logger::name_i()
{
//Go to sleep for a while to simulate slow I/O device
ACE_OS::sleep(2);
return name_;
}
最后的代码段演示应用代码,它实例化
Logger主动对象,并用它来进行日志记录:
例
5-3e//Client or application code.
int main (int, char *[])
{
//Create a new instance of the Logger task
Logger *logger = new Logger;
//The Futures or IOUs for the calls that are made to the logger.
ACE_Future
ACE_Future
//Activate the logger
logger->open(0);
//Log a few messages on the logger
for (size_t i = 0; i < n_loops; i++)
{
char *msg= new char[50];
ACE_DEBUG ((LM_DEBUG,
Issuing a non-blocking logging call\n"));
ACE_OS::sprintf(msg, "This is iteration %d", i);
logresult= logger->logMsg(msg);
//Don’t use the log result here as it isn't that important...
}
ACE_DEBUG((LM_DEBUG,
"(%t)Invoked all the log calls \
and can now continue with other work \n"));
//Do some work over here...
// ...
// ...
//Find out the name of the logging task
name = logger->name ();
//Check to "see" if the result of the name() call is available
if(name.ready())
ACE_DEBUG((LM_DEBUG,"Name is ready! \n"));
else
ACE_DEBUG((LM_DEBUG,
"Blocking till I get the result of that call \n"));
//obtain the underlying result from the future object.
const char* task_name;
name.get(task_name);
ACE_DEBUG ((LM_DEBUG,
"(%t)==> The name of the task is: %s\n\n\n", task_name));
//Wait for all threads to exit.
ACE_Thread_Manager::instance()->wait();
}
客户代码在
Logger主动对象上发出若干非阻塞式异步调用。注意这些调用看起来就像是在针对常规被动对象一样。事实上,调用是在另一个单独的线程控制里执行。在发出调用记录多个消息后,客户发出调用来确定任务的名字。该调用返回一个期货给客户。于是客户就开始使用ready()方法去检查结果是否已在期货对象中设置。然后它使用get()方法去确定期货的底层值。注意客户的代码是何等的优雅,没有用到线程、同步,等等。所以,主动对象模式可以使你更加容易地编写你的客户代码。
