这一章介绍前面提到过的
ACE_Task类,另外还介绍了主动对象模式。基本上这一章将涵盖两个主题。首先,它将讲述怎样将ACE_Task构造作为高级面向对象机制使用,用以编写多线程程序。其次,它将讨论怎样在主动对象模式[II]中使用ACE_Task。主动对象
那么到底什么是主动对象呢?传统上,所有的对象都是被动的代码段,对象中的代码是在对它发出方法调用的线程中执行的。也就是,调用线程(
calling threads)被“借出”,以执行被动对象的方法。而主动对象却不一样。这些对象持有它们自己的线程(甚或多个线程),并将这个线程用于执行对它们的任何方法的调用。因而,如果你想象一个传统对象,在里面封装了一个线程(或多个线程),你就得到了一个主动对象。
例如,设想对象
“A”已在你的程序的main()函数中被实例化。当你的程序启动时,OS创建一个线程,以从main()函数开始执行。如果你调用对象A的任何方法,该线程将“流过”那个方法,并执行其中的代码。一旦执行完成,该线程返回调用该方法的点并继续它的执行。但是,如果”A”是主动对象,事情就不是这样了。在这种情况下,主线程不会被主动对象借用。相反,当”A”的方法被调用时,方法的执行发生在主动对象持有的线程中。另一种思考方法:如果调用的是被动对象的方法(常规对象),调用会阻塞(同步的);而另一方面,如果调用的是主动对象的方法,调用不会阻塞(异步的)。
ACE_Task
是ACE中的任务或主动对象“处理结构”的基类。在ACE中使用了此类来实现主动对象模式。所有希望成为“主动对象”的对象都必须从此类派生。你也可以把ACE_TASK看作是更高级的、更为面向对象的线程类。当我们在前一章中使用
ACE_Thread包装时,你一定已经注意到了一些“不好”之处。那一章中的大多数程序都被分解为函数、而不是对象。这是因为ACE_Thread包装需要一个全局函数名、或是静态方法作为参数。随后该函数(静态方法)就被用作所派生的线程的“启动点”。这自然就使得程序员要为每个线程写一个函数。如我们已经看到的,这可能会导致非面向对象的程序分解。相反,
ACE_Task处理的是对象,因而在构造OO程序时更便于思考。因此,在大多数情况下,当你需要构建多线程程序时,较好的选择是使用ACE_Task的子类。这样做有若干好处。首要的是刚刚所提到的,这可以产生更好的OO软件。其次,你不必操心你的线程入口是否是静态的,因为ACE_Task的入口是一个常规的成员函数。而且,我们会看到ACE_Task还包括了一种用于与其他任务进行通信的易于使用的机制。重申刚才所说的,
ACE_Task可用作:- 更高级的线程(我们称之为任务)。
- 主动对象模式中的主动对象。
ACE_Task
的结构在本质上与基于Actor的系统[III]中的“Actor”的结构相类似。该结构如下所示:

图
5-1任务结构示意图
图
5-1说明每个任务都含有一或多个线程,以及一个底层消息队列。各个任务通过这些消息队列进行通信。但是,消息队列并非是程序员需要关注的对象。发送任务可以使用putq()调用来将消息插入到另一任务的消息队列中。随后接收任务就可以通过使用getq()调用来从它自己的消息队列里将消息提取出来。因而,你可以设想一个系统,由多个自治的任务(或主动对象)构成,这些任务通过它们的消息队列相互通信。这样的体系结构有助于大大简化多线程程序的编程模型。
5.2.2创建和使用任务
如上面所提到的,要创建任务或主动对象,你必须从
ACE_Task类派生子类。在子类派生之后,必须采取以下步骤:
下面的例子演示怎样去创建任务:
例
5-1#include "ace/OS.h"
#include "ace/Task.h"
class TaskOne: public ACE_Task
{
public:
//Implement the Service Initialization and Termination methods
int open(void*)
{
ACE_DEBUG((LM_DEBUG,"(%t) Active Object opened \n"));
//Activate the object with a thread in it.
activate();
return 0;
}
int close(u_long)
{
ACE_DEBUG((LM_DEBUG, "(%t) Active Object being closed down \n"));
return 0;
}
int svc(void)
{
ACE_DEBUG((LM_DEBUG,
"(%t) This is being done in a separate thread \n"));
// do thread specific work here
//.......
//.......
return 0;
}
};
int main(int argc, char *argv[])
{
//Create the task
TaskOne *one=new TaskOne;
//Start up the task
one->open(0);
//wait for all the tasks to exit
ACE_Thread_Manager::instance()->wait();
ACE_DEBUG((LM_DEBUG,"(%t) Main Task ends \n"));
}
上面的例子演示怎样把
ACE_Task当作更高级的线程来使用。在例子中,TaskOne类派生自ACE_Task,并实现了open()、close()和svc()方法。在此任务对象实例化后,程序就调用它的open()方法。该方法依次调用activate()方法,致使一个新线程被派生和启动。该线程的入口是svc()方法。主线程等待主动对象线程终止,然后就退出进程。
