参考:《ACE自适配通信环境中文技术文档》
1.主动对象模式介绍
主动对象模式用于降低方法执行和方法调用之间的耦合。该模式描述了另外一种更为透明的任务间通信方法。
该模式使用ACE_Task类作为主动对象。在这个对象上调用方法时,它就像是常规对象一样。就是说,方法调用是通过同样的->操作符来完成的,其不同在于这些方法的执行发生于封装在ACE_Task中的线程内。
2.主动对象模式工作原理
2.1主动对象模式的参与者
1.主动对象(基于ACE_Task)。
2.ACE_Activation_Queue
3.若干ACE_Method_Object(主动对象的每个方法都需要有一个方法对象)。
4.若干ACE_Future对象(每个要返回结果的方法都需要这样一个对象)。
2.2主动对象模式的参与者的具体工作
1.ACE_Task创建和封装线程
2.ACE_Method_Object
必须为所有要从客户(框架的使用者)异步调用的方法编写方法对象。每个方法对象都派生自ACE_Method_Object,并会实现它的call()方法(call方法必须包含1.执行在主动对象中实际编写的方法,2.设置返回值)。每个方法对象还维护上下文信息(包括方法所对应的主动对象的引用,方法的参数的引用和返回值Future对象等)可以把方法对象看作是方法调用的“罩子”(closure)。客户发出方法调用,使得相应的方法对象被实例化,并被放入启用队列(activation queue)中。方法对象是命令(Command)模式的一种形式。
3.ACE_Activation_Queue
ACE_Activation_Queue是一个队列,方法对象在等待执行时被放入其中。因而启用队列中含有所有等待调用的方法(以方法对象的形式)。封装在ACE_Task中的线程保持阻塞,等待任何方法对象被放入启用队列。一旦有方法对象被放入,任务就将该方法对象取出,并调用它的call()方法。call()方法应该随即调用该方法在ACE_Task中的相应实现。在方法实现返回后,call()方法在ACE_Future对象中设置(set())所获得的结果。
4.ACE_Future
使用ACE_Future对象获取它在主动对象上发出的任何异步操作的结果。一旦客户发出异步调用,立即就会返回一个ACE_Future对象。于是客户就可以在任何它喜欢的时候去尝试从“期货”(future)对象中获取结果。如果客户试图在结果被设置之前从期货对象中提取结果:使用get()方法,客户将会阻塞。如果客户不希望阻塞,它可以通过使用ready()调用来轮询(poll)期货对象(ready()方法检查相应的结果的指针是否为空,为空,NotReady,不为空,Ready)。如果结果已被设置,该方法返回1;否则就返回0。ACE_Future对象基于“多态期货”(polymorphic futures)的概念。
///////////////////////////////////////////////////////////////////////
3.例子
下面的例子演示主动对象模式是怎样实现的。在此例中,主动对象是一个“Logger”(日志记录器)对象。Logger使用慢速的I/O系统来记录发送给它的消息。因为此I/O系统很慢,我们不希望主应用任务的执行因为相对来说并非紧急的日志记录而减慢。为了防止此情况的发生,并且允许程序员像发出普通的方法调用那样发出日志调用,我们使用了主动对象模式。
//Main.CPP
#pragma comment(lib,"ACEd.lib")
#include "ace/Future.h"
#include "ace/OS.h"
#include "ace/Log_Msg.h"
#include "ace/Thread_Manager.h"
#include "Log.h"
typedef unsigned long u_long;
int main (int, char *[])
{
//创建一个Logger的Task的任务
Logger * logger = new Logger;
//ACE_Future 对象记录函数的返回值
ACE_Future<u_long> logresult;
ACE_Future<const char *> name;
//启动Logger任务(线程)
logger->open(0);
//在Logger上记录一些信息
size_t n_loops = 5;
for (size_t i = 0; i < n_loops; i++)
{
char * msg= new char[50];
ACE_DEBUG ((LM_DEBUG,"(%t)Issuing a non-blocking logging call\n"));
ACE_OS::sprintf(msg, "(%t)This is iteration %d", i);
logresult= logger->logMsg(msg);
}
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,"(%t)Name is ready!\n"));
else
ACE_DEBUG((LM_DEBUG,"(%t)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",));
//Wait for all threads to exit.
ACE_Thread_Manager::instance()->wait();
getchar();
return 0;
}
|
///////////////////////////////////////////////////////////////////////////////
Log.h==>主动对象
#pragma once
#include "ace/Task.h"
#include "ace/Future.h"
#include "ACE/Activation_Queue.h"
class Logger: public ACE_Task
{
public:
//Initialization and termination methods
Logger();
virtual ~Logger(void);
virtual int open (void *);
virtual int close (u_long flags = 0);
//The entry point for all threads created in the Logger
virtual int svc (void);
///////////////////////////////////////////////////////
//Methods which can be invoked by client asynchronously.
///////////////////////////////////////////////////////
//Log message
ACE_Future<u_long> logMsg(const char* msg);
//Return the name of the Task
ACE_Future<const char*> name (void);
///////////////////////////////////////////////////////
//Actual implementation methods for the Logger
///////////////////////////////////////////////////////
u_long logMsg_i(const char *msg);
const char * name_i();
private:
char *name_;
ACE_Activation_Queue activation_queue_;
};
|
Log.cpp==>主动对象
#pragma once
#include "Log.h"
#include "LogMsgMo.h"
#include "Name_Mo.h"
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)
{
ACE_DEBUG((LM_DEBUG, "(%t) 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 activationqueue. Once a method object is inserted onto the activation queue thethread wakes up, dequeues the method object and then invokes thecall() 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<ACE_Method_Object> 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<u_long> Logger::logMsg(const char* msg)
{
ACE_Future<u_long> resultant_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<const char*> Logger::name (void)
{
ACE_Future<const char*> resultant_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,"(%t) 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()
{
ACE_DEBUG((LM_DEBUG,"(%t) Getting Name:...\n"));
//Go to sleep for a while to simulate slow I/O device
ACE_OS::sleep(2);
return name_;
}
|
////////////////////////////////////////////////////////////////////////////////
下面两个类是方法对象
logMsg_MO.h==>向日志系统中写入文件
#pragma once
#include "ace/Method_Object.h"
#include "ace/Future.h"
#include "Log.h"
class logMsg_MO: public ACE_Method_Object
{
public:
//Constructor which is passed a reference to the active object, the parameters for the method, and a reference to the future which contains the result.
//(主动对象的引用,方法的参数的引用和Future对象)
logMsg_MO(Logger * logger, const char * msg,
ACE_Future<u_long> &future_result);
virtual ~logMsg_MO();
//The call() method will be called by the Logger Active Object class, once this method object is dequeued from the activation queue. This is implemented so that it does two things. First it must execute the actual implementation method (which is specified in the Logger class. Second, it must set the result it obtains from that call in the future object that it has returned to the client.Note that the method object always keeps a reference to the same future object that it returned to the client so that it can set the
result value in it.
//1.执行在主动对象中实际编写的方法,2.设置返回值
virtual int call (void);
private:
Logger * logger_;
const char* msg_;
ACE_Future<u_long> future_result_;
};
|
logMsg_MO.cpp==>向日志系统中写入文件
#pragma once
#include "LogMsgMo.h"
logMsg_MO::logMsg_MO(Logger * logger, const char * msg, ACE_Future<u_long> &future_result):logger_(logger), msg_(msg),(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_));
}
|
Name_Mo.h==>获取线程的名称
#pragma once
#include "ace/Method_Object.h"
#include "ace/Future.h"
#include "Log.h"
class name_MO: public ACE_Method_Object
{
public:
//Constructor which is passed a reference to the active object, theparameters for the method, and a reference to the future which contains the result.
name_MO(Logger * logger, ACE_Future<const char*> &future_result);
virtual ~name_MO();
//The call() method will be called by the Logger Active Object class, once this method object is dequeued from the activation queue. This is implemented so that it does two things. First it must execute the actual implementation method (which is specified in the Logger class. Second, it must set the result it obtains from that call in the future object that it has returned to the client.Note that the method object always keeps a reference to the same future object that it returned to the client so that it can set the
result value in it.
virtual int call (void);
private:
Logger * logger_;
ACE_Future<const char*> future_result_;
};
|
Name_Mo.cpp==>获取线程的名称
#pragma once
#include "Name_Mo.h"
//Implementation for the name_MO method object.
//Constructor
name_MO::name_MO(Logger * logger, ACE_Future<const char*> &future_result):
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 ());
}
|
4.程序的运行结果
1-4行主线程执行
5行Logger线程执行
6行主线程执行
7行Logger线程执行
8-15行主线程执行
16行主线程等待执行结果
17-32行Logger线程执行
33行主线程执行,获得返回结果!
阅读(3335) | 评论(1) | 转发(0) |