ACE_Task

一、概述
         ACE_Task 是ACE中的任务或主动对象“处理结构”的基类。ACE使用此类来实现主动对象模式。所有希望成为“主动对象”的对象都必须由此类派生。同时可将它看作是更高级的、更为面向对象的线程。
ACE_Task 处理的是对象,因此更有利于构造OO程序,产生更好的OO软件,而且,它还包括了一种用于
与其他任务通信的易于使用的机制。
ACE_Task 可用作:
<1>更高级的线程(常称其为任务)
<2>主动对象模式中的主动对象
PS.ACE任务:
        每个任务都含有一或多个线程,以及一个底层消息队列。各个任务通过消息队列进行通信。至于消息队列实现的内在细节程序员不必关注。发送任务用putq() 将消息插入到另一任务的消息队列中,接收任务通过使用getq()将消息提取出来。这样的体系结构大大简化了多线程程序的编程模型。
二、创建和使用任务的步骤
       从 ACE_Task 类派生的子类应实现以下业务逻辑:
<1>实现服务初始化和终止方法。
      open()方法应该包含所有专属于任务的初始化代码。其中可能包括诸如连接控制块、锁和内存这样的资源。close()方法用于终止。
<2>调用启用(Activation)方法。
       在主动对象实例化后,必须通过调用activate()启用它。要在主动对象中创建的线程数目及其它参数,被传递给activate()方法。它将使svc()方法成为所有它生成的线程的启动点。
<3>实现服务专有的处理方法。
       在主动对象被启用后,各个新线程在 svc() 方法中启动。程序员必须在子类中定义此方法。

ACE_Task 基本应用框架

ACE的 ACE_Task 框架提供了一种基于消息的编程模式,可以Windows编程的消息循环进行类比。

 


ACE_Task

Windows 消息循环

说明

消息类型

ACE_Message_Block*

MSG

Windows消息用MSG结构表示, ACE_Task 中 因为不能预计各种应用中消息的类型,所以ACE_Message_Block基本上可以理解为是对一个指针的封装,这个指针指向实际的一块内存或是一个对 象等等。在创建ACE_Message_Block时,可以指定是由ACE_Message_Block来管理内存(构造函数中指定一个 size_t类型的大小),还是由我们自己管理内存(构造函数中指定一个指针)。而一个ACE_Message_Block类型的指针,就是一个消息,我 们通过传递它来进行逻辑的业务处理。

发送消息

ACE_Task ::putq

SendMessage

事实上,到底用SendMessage还是PostMessage与 ACE_Task ::putq来进行类比,我很为难,PostMessage发送一个消息后立刻返回,这与通常的 ACE_Task ::putq行为非常类似,因为 ACE_Task 是运行在另外一个线程上, ACE_Task ::putq只是完成将消息插入到消息队列的工作,理论上它应该立刻返回,但实际上, ACE_Task 的消息队列有容量大小限制,这个限制由我们自己限定,当当前消息队列满时, ACE_Task ::putq将阻塞一直到可以插入,这时候就比较类似与SendMessage,GetMessage和

取出消息

ACE_Task ::getq

GetMessage

ACE_Task ::getq在当前消息队列没有消息时都会阻塞到有消息可用为止,所以对于它们的使用比较类似,通常会写一个消息循环函数

BOOL bRet;MSG msg;while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0){     if (bRet == -1) {             // handle the error and possibly exit }    else {             TranslateMessage(&msg);             DispatchMessage(&msg);       }}         

 

 

 

ACE_Message_Block * msg;while(getq(msg) != -1)     // int putq (ACE_Message_Block *, ACE_Time_Value *timeout = 0);{ // process msg here}   通过TranslateMessage和DispatchMessage,

消息处理函数

默认没有提供

WNDPROC

Windows将消息投递到相映窗口的WNDPROC上, ACE_Task 没有提供类似与WNDPROC的回调函数,如果愿意,我们可以在 ACE_Task 上写出类似的结构,而通常,我们直接在消息循环中编写处理消息的代码



   尽管看起来 ACE_Task 提供的消息系统与WIndows的消息系统很象,但实际上,它们还是有比较大的区别,要搭架一个基于 ACE_Task 的消息系统,通常要做如下的步骤:

  • 编写一个派生自 ACE_Task 的类,指定它的同步模式
    ACE_Task 的消息队列可以由多个处理线程共享使用,所以需要提供同步模式,例如 ACE_MT_SYNCH和ACE_NULL_SYNCH分别表示基于多线程的同步和不使用同步,这个参数是 ACE_Task 的一个模板参数。
    class My_Task : public
    ACE_Task <ACE_MT_SYNCH>{public: virtual int svc();}
  • 重载 ACE_Task 的 svc 方法,编写消息循环相关的代码
    int My_Task::svc(){ ACE_Message_Block * msg; while(getq(msg) != -1) // int putq (ACE_Message_Block *, ACE_Time_Value *timeout = 0); {   // process msg here }} svc 方法相当与处理线程的入口方法。
  • 假设 My_Task是一个基于 ACE_Task 的类,创建一个唯一的My_Task实例,这个可以通过
    typedef ACE_Singleton<MyTask, SYNCH_METHOD> MYTASK;
    然后总是使用MYTASK::instance方法来获取一个My_Task的指针来完成。
  • 在适当位置(一般是程序开始的时候),让My_Task开始工作
    MYTASK::intance()->activate(
    THR_NEW_LWP | THR_JOINABLE |THR_INHERIT_SCHED , // 线程创建的属性
    n_threads = 1, // 线程的数目,即有多少处理线程
    ...)
  • 在有消息发生的时候发送消息 ACE_Message_Block * msg;// fill the msg...MYTASK::intance()->putq(msg);

   最后考虑一个使用 ACE_Task 的实例,在一个编写WEB服务器的项目中,类 Request_Handler负责处理HTTP请求,Request_Hanlder派生自 ACE_Task , 当有请求时,其他的代码将Http请求构造成一个ACE_Message_Block,并调用Request_Handler的putq方法将请求插入消 息队列,Request_Handler配置为根据CPU的数目创建处理线程,Request_Handler的svc方法从队列中获取请求进行处理,然 后将处理的结果构造成为一个ACE_Message_Block,插入到Response_Handler的消息队列,Response_Handler 也派生自 ACE_Task ,但它只有一个处理线程,它仅仅将相应的数据写回给客户端。

示例: P2P_Task_CDN_PrgmAgent task 类 svc 方法中不能访问到我的成员变量

class P2P_Task_CDN_PrgmAgent : public P2P_Task_Base
{
private:
std::string m_transactionip;
unsigned int m_transactionport;
std::map<std::string,unsigned int> m_esaddrport;

ACE_Recursive_Thread_Mutex recursive_mutex_; // 锁


public:

P2P_Task_CDN_PrgmAgent(P2P_Application * pApplication,UInt32 taskid);

virtual ~P2P_Task_CDN_PrgmAgent(void);


virtual bool Initialize()

{
return true;
}

void get_all_interfaces();


virtual int svc();


bool SendFileToEs();


bool ProcessMessage(P2P_Message_Base *pMsg,

ACE_Message_Block *pCurrentMessageBlock);
};

int P2P_Task_CDN_PrgmAgent:pen()


{


m_transactionip = "127.0.0.1";

m_transactionport = 8888;

}


int P2P_Task_CDN_PrgmAgent::svc()

{
while(1)
{
ACE_Message_Block * pMessage = 0;
P2P_Message_Base * pMsg = 0;
{
ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, guard, recursive_mutex_,0);
this->getq(pMessage);
assert(pMessage);
pMsg = P2P_Message_Base:eserialize(pMessage->base());
pMessage->release();
}

assert(pMsg);


char addr[20];

memset(addr,0,sizeof(addr));
ACE_OS::inet_ntop(AF_INET,&pMsg->uiParameter1,addr,sizeof(addr));

ACE_DEBUG((LM_DEBUG,"drive ES:%p%s",addr));


//怪异的是下一行,总是不能得到 m_transactionip 的值,每次都是 ""


int ret = TransFile("c://twz.mp4",addr,

pMsg->uiParameter2,m_transactionip,m_transactionport);
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值