文章摘要: ADAPTIVE Communication Environment (ACE) 是一种免费开放原代码的面向对象框架结构,该结构实现了许多并行通信软件的核心设计模式. ACE提供丰富的C++ wrapper facades, 以及可跨平台执行通信软件的基本任务的框架对象。ACE提供的基本任务包括事件分离与事件处理的分发, 信号量处理,服务初始化 , 进程间通信, 共享内存管理, 消息路由, 分布式服务的动态配置, 并发执行与同步。
ADAPTIVE Communication Environment (ACE) 是一种免费开放原代码的面向对象框架结构,该结构实现了许多并行通信软件的核心设计模式. ACE提供丰富的C++ wrapper facades, 以及可跨平台执行通信软件的基本任务的框架对象。ACE提供的基本任务包括事件分离与事件处理的分发, 信号量处理,服务初始化 , 进程间通信, 共享内存管理, 消息路由, 分布式服务的动态配置, 并发执行与同步。
ACE 的使用对象是面向开发高性能与实时通信服务应用的开发人员。它可以简化实现进程见通信,event demultiplexing , 直接动态链接explicit dynamic linking,以及并发处理功能的面向对象网络应用与服务的开发过程。 同时, ACE 通过在运行过程中动态将服务连接到应用中并在一个或多个进程或线程中执行这些服务这种方式实现了系统的自动配置与重新配置。
ACE 仍在不断的发展,它的应用前景非常光明。ACE的商业用途的支持由 Riverace 公司使用公开原代码方式进行. 同时,许多ACE 开发小组的成员正在进行 ACE ORB (TAO)的开发工作。
1. 使用ACE的优点 使用ACE的主要优点包括:
高可移植性 - ACE部件使书写某一操作系统的并行网络应用和快速移植到许多其他操作系统平台变的非常容易。而且,因为ACE 是开发原代码、免费的软件,你不需担心在特定的操作系统或编译配置时被卡住。
增强的软件质量 - ACE部件是使用许多可增强通信软件关键的质量特性(如灵活性、可扩展性、可重用性与模块化等)的重要设计模式来设计的。
高效率与可预见性predictability - ACE通过小心的设计来支持对于不同应用质量的服务(application quality of service,QoS)的需求,包括对于延迟敏感的应用使用较少的延迟,要求较强通信带宽的应用提供高性能的服务,以及对实时性应用的可预见性等服务。
可容易的整合为高级的中间件 -- ACE 在TAO提供了可重用的部件与模式。而TAO是一个为高性能与实时系统应用优化过的,通过开放原代码实现了CORBA兼容标准。这样, ACE与TAO被设计用来协同工作来实现复杂的中间件解决方案。
2. ACE的结构与功能 下图说明了ACE关键的部件以及他们之间的层次关系。
图表 1
图中的结构与层次关系在下面描述。
3. ACE接口层(ACE Adapter Layer) 该层在C编写的本地操作系统API之上。该接口层使在ACE中的其他层与部件与下面的平台相关的操作系统API隔离开来:
并发与同步 - ACE接口层封装了操作系统的多线程、多进程与同步机制相关的API。
进程间通信与共享内存-- ACE接口层封装了操作系统的本地与远程进程间通信,和共享内存管理的相关API。
事件分离机制 - ACE的接口层封装了操作系统中,有关同步和异步分离基于I/O、计时器、信号量、和同步事件的部分功能。
显式动态链接-- ACE接口层封装了操作系统的显式动态链接相关的API,该功能允许应用服务不管在安装与运行时都可被配置。
文件系统机制 -- ACE接口层封装了操作系统的文件系统API来操作文件与目录。
ACE操作系统接口层的移植性使它可以在许多不同的操作系统平台上运行。 ACE已经在许多操作系统平台上被移植并被测试 包括Win32 (i.e., WinNT 3.5.x, 4.x, 2000, Win95/98, and WinCE using MSVC++, Borland C++ Builder, and IBM's Visual Age on Intel and Alpha platforms), 许多UNIX的版本 (e.g., Solaris 1.x and 2.x on SPARC and Intel, SGI IRIX 5.x and 6.x, DG/UX, HP-UX 9.x, 10.x, and 11.x, DEC/Compaq UNIX 3.x and 4.x, AIX 3.x and 4.x, DG/UX, UnixWare, SCO, and freely available UNIX implementations, such as Debian Linux 2.x, RedHat Linux 5.2 and 6.0, FreeBSD, and NetBSD), 实时操作系统(e.g., LynxOS, VxWorks, Chorus ClassiX 4.0, QnX Neutrino, and PSoS), MVS OpenEdition, and CRAY UNICOS. 单一的原代码树被用到所有操作系统平台上。
ACE当前也有JAVA版本。
因为有ACE操作系统接口平台的抽象,单一的原代码树被用到所有操作系统平台上,该设计简化了ACE的可移植性与可维护性。
4. 操作系统接口的C++包装接口(C++ Wrapper Facades for OS Interfaces) 我们完全可以直接在ACE操作系统接口层之上开发高移植性的C++程序。但是,更多的开发者选择使用如图所示ACE的C++封装层。C++封装层通过提供封装并增强本地操作系统并发控制、通信、内存管理、事件分离、动态链接,与文件系统API,提供类型安全接口简化应用的开发。应用可通过有选择的继承、聚集或实例化下列对象来使用这些封装:
并发与同步部件-ACE抽象了本地操作系统的多线程和多进程机制,如互斥,信号量来创建如活动对象(Active Objects)与多态未来(Polymorphic Futures)等高级面向对象并发抽象。
进程间通信与文件部件 --ACE C++ 包装者封装了本地和远程的进程间通信机制如:接口(sockets), TLI, UNIX FIFOs与STREAM pipes, 以及Win32 的命名管道(Named Pipes). ACE C++ 包装者封装了操作系统当中文件系统的APIs。
内存管理部件 - ACE的内存管理部件对于管理进程间共享内存和进程外栈内存的动态分配与回收,提供了灵活、可扩展的抽象机制。
C++包装者提供了许多与操作系统接口层同样的特性。但是,这些特性不是使用单独的C函数构造的,他们是使用C++类与对象来构造的。这些面向对象的包可减少直接学习与使用ACE所花费的精力。
比如,由于C++包装者是强类型的,所以,使用它可以增强应用的健壮性。因此,编译器可以在编译时间检测到系统类型不匹配而不是在运行时间。相反,对于C级别的操作系统的一些API如,接口、文件系统I/O等,在运行时间之前几乎不能检查到系统类型的不匹配 。
ACE使用许多技术来减少或最小化执行成本。如ACE通过它的操作系统接口层和C++包装者提供的附加的类型安全性与不同的抽象级别,使用C++扩展的内联性(inlining)减少相关的方法调用的成本。同时,ACE注意避免在关键任务的包装者上使用需方法,如接口与文件I/O的send/recv方法。
5. 框架结构(Frameworks) ACE同时包含了高级网络编程框架,该框架集成且增强了低一级的C++包装接口。该框架支持动态地将并发分布式服务配置成为应用。ACE的框架结构部分包含以下部件:
事件分离器部件(Event demultiplexing components)--ACE的接收者(Reactor)与超动者(Proactor)是可扩展的、面向对象的事件分离器。这些分离器可以基于各种类型的I/O、计时器、信号量、与同步相关事件来分发各种应用相关的操作句柄。
服务初始化部件(Service initialization components)--ACE 接收者(Acceptor)和连接者(Connector)部件是分别从特定应用任务中分离出来的,在服务初始化完成后,执行主动与被动初始化角色。
服务配置部件(Service configuration components )-- ACE服务配置管理者可以配置应用,使其可在安装或运行时组装服务。
分层流部件(Hierarchically-layered stream components) -- ACE流部件简化了通信软件应用的开发过程,比如用户级的协议堆栈,它可由层次结构的服务构成。
ORB接口部件(ORB adapter components) -- ACE可以通过其ORB接口部件,无缝地集成单线程和多线程的CORBA应用。
使用ACE框架部件可促进通信软件的开发。使用它,通信软件可以在不用修改、重新编译、重新链接、或是经常重新启动应用程序的情况下,更新或扩展应用。该灵活性在ACE中是通过结合以下方面实现的:
a) C++语言特性,如模板、继承、和动态帮定。
b) 设计模式,如抽象类工厂、策略、以及服务配置器等。
c) 操作系统机制,如显式的动态链接与多线程。
6. 分布式服务与部件(Distributed Services and Components) 除了它的操作系统接口层,C++封装层和各种框架部件外,ACE同时提供一套分布式服务标准库,这些库被分成可自含的包。尽管这些服务部件不是严格的ACE框架库,但这些部件在ACE中有以下角色:
给出可重用的应用代码片段-这些服务部件提供了如命名、事件路由、日志、时间同步与网络封锁等一般分布式应用任务的可重用实现。
给出ACE部件的基本用例的示范--这些分布式服务同时证明了如何使用象 反应者(Reactors),服务配置( Service Configurators),接收者与连接者( Acceptors and Connectors),活动对象(Active Objects),以及进程间通信的封装(IPC wrappers) 等ACE部件,有效开发灵活、高效和可靠的通信软件。
7. 高级分布式计算中间件对象(Higher-level Distributed Computing Middleware Components) 即使使用象ACE这样的通信框架,开发健壮的、可扩展并且高效的通信程序是非常有挑战性的工作。开发人员必须掌握大量的复杂操作系统与通信概念,比如:
网络寻址与服务识别 描述转换, 如在异构系统间和不同处理器的字节循序间的加密、压缩与网络字节顺序转换。
进程与线程的创建与同步。
系统调用和对于本地与远程的进程间通信机制的类库常规接口。
通过使用如CORBA,DCOM或JAVA RMI等高级的分布计算中间件,有可能减轻部分开发通信应用的复杂程度。高级分布计算中间件包含有服务器端与客户端两部分,并自动完成许多繁杂且易于出错的分布式应用开发工作,比如:
验证,授权与数据安全。
服务的查找与帮定。
服务的注册与激活。
对于事件的分离与发送。
在面向字节流通信协议之上实现如TCP协议的消息框架。
如网络字节码转换或参数排列等的描述转换问题处理。
为了给通信软件开发者提供这些特性,在ACE中打包了下面的高级中间件应用:
ACE ORB (TAO) - TAO是使用ACE中提供的框架结构对象与模式实现的针对高效与实时系统的CORBA应用。TAO中包含了网络接口,操作系统,通信协议以及CORBA中间件对象与相关特性。TAO基于标准的OMG的CORBA参考模型, 并且针对传统ORBS对于高效和实时应用系统的缺点,加入了相应的改善设计。TAO,与 ACE一样,都是免费的开放原代码的软件。
JAWS -- JAWS TAO是使用ACE中提供的框架结构对象与模式实现的针对高效与实时系统的可适应性的WEB服务器。JAWS 被设计为框架的框架。JAWS的总体框架包含以下部件与框架: 一个事件调配者,并发策略 ,I/O 策略,协议管道 , 协议处理者,以及缓冲的虚拟文件系统。通过结合与扩展ACE中的部件,每种框架被设计为一套可协作的对象。JAW也是免费的开放原代码的软件。
ACE源代码目录结构
2008-03-19 16:40
ACE(ADAPTIVE Communication Environment),中文的意思就是自适配通讯环境,ACE是一个用于开发网络程序的优秀的C++的框架,在国外有很广泛的使用,在国内一些大的开发通讯产品的公司也有使用。我接触ACE也有一段时间了,虽然时间不长,但我还是感觉到ACE确实是一个好东西,对于丰富自己的知识面有很大的帮助。虽然我们项目目前是采用C语言来开发,但是当接触ACE后,你会发现“喔,原来程序还可以这样”。例如:我觉得ACE里面Reactor框架就是一个非常的东西,我们在开发网络程序的时候,常常采用poll来监视各种网络事件,但当采用该框架后,你现在只是需要关系你的业务逻辑,当发生特定的网络事件后,框架会回调你的业务逻辑。其实按照这个思路,我们完全可以用C来实现类似的功能,当你完成这个后,你会发现你原来用C语言写的过程风格的代码竟然有了OO的味道。
ACE确实是好东西,但也不是能轻松的就能掌握的,我们还需要一步一步的来蚕食这个大象。
万丈高楼平地起,首先我们还是了解一下ACE的目录结构,从整体上对ACE有一个认识,为今后的进一步学习打下一个基础。
解开ACE的压缩包后,你会发现一个ACE_wrappers目录,这个目录也就是ACE的HOME目录,它下面还包含着一些子目录:
ace:这个目录是ACE中最重要的目录,它包含了ACE的所有源码,但遗憾的是,ACE的所有源文件和头文件全部杂乱的堆在这个目录里,这可能也是很多开源软件的缺点。其实ACE的代码完全可以按照不同的功能进行不同目录的划分,例如:Reactor框架和thread框架代码完全可以划分开,我想一个代码组织良好的ACE,将会给大家的学习带来极大的好处,我将在后面的文章里给出ACE代码划分的方法; ACEXML:这个目录包含了用ACE实现的一个XML解析器; apps:这个目录包含了用ACE来实现的一些较大的应用程序,例如:JAWS,一个WEB服务器;
ASNMP:基于ACE的SNMP协议实现; bin:包含里用例方便开发的perl脚本程序,例如:在WIN32上开发DLL时候,需要导出DLL的接口; docs:ACE的一些帮助文档,其中ACE-subsets.html文档,对我们划分ACE的代码有很大的帮助;
examples:是用ACE来编写的一些例子程序,方便更好的学习和理解ACE; include:也是ACE中一个比较重要的目录,它包含了在不同的平台上编译时候的编译规则,库的编译规则等; netsvcs:一些基于ACE的在分布式系统中常用的程序,例如:分布式系统日志系统,网络锁,时间同步等;
TAO:基于ACE的实时CORBA实现,TAO在分布式系统中使用相当广泛,也是一个不可多得的好资源; tests:用来对ACE进行回归测试,也提供了一个学习ACE的很好的例子代码;
***********************************************************************************************************************************
前几篇文章也提到过,ACE的所有源文件和头文件都杂乱堆在了ACE_wrappers/ace目录下。这样的代码组织方式给学习ACE带来了很大的困难,很多朋友在看到ace目录下庞大的代码的时候,几乎就失去了学习ACE的信心^_^。因此,我们有必要对ACE的代码进行重新组织,以降低学习曲线。下面,我将给出我对ACE源码的划分方法。其实,我也是刚学习ACE没有多久,对ACE的了解还甚少,所以,我的源码划方式法不一定十分正确,这里共享出来,仅供大家参考。
其实,在ACE的帮助文档里,ACE-subsets.html和ACE-categories.html,这两个文档对指导ACE的源码划分起到了很大的作用,否则,我刚刚接触ACE,就想对其进行源码划分,是不可能完成的。ACE-subsets.html,这个文档主要介绍了ACE的library subsetting。正常情况下,在编译完ACE后,只会产生一个ACE的库。我们可以根据该文档的介绍,简单的修改一下Makefile,就可以对ACE的库进行子集化,我们可以编译出OS、Thread等这样的子库。ACE-categories.html,这个文档对ACE中的代码进行了一些功能上的分类。具体大家可以详细的参考一下这两个文档,这两个文档对学习ACE还是有一定的帮助的。
在ACE的源代码目录ace下,我将建立很多子目录,来对ACE的代码进行按功能分类:
ACE_OS:该目录里包含的代码是OS的API的wrapper,也就是ACE的OS适配层; 包含代码: ARGV.cpp OS_Memory.cpp Argv_Type_Converter.cpp OS_QoS.cpp Base_Thread_Adapter.cpp OS_String.cpp Basic_Types.cpp OS_TLI.cpp Copy_Disabled.cpp OS_Thread_Adapter.cpp Env_Value_T.cpp Sched_Params.cpp Handle_Set.cpp Template_Instantiations.cpp Makefile Thread_Hook.cpp OS.cpp Time_Value.cpp OS_Dirent.cpp OS_Errno.cpp OS_Log_Msg_Attributes.cpp
ACE_Codec:该目录包含的是ACE的各种编码类型的处理代码,目前只包含了BASE64编码的处理; 包含代码:Codecs.cpp Makefile
ACE_Connection:该目录包含的是ACE中的Acceptor-Connector框架代码和异步通讯类代码; 包含代码:Acceptor.cpp Connector.cpp Asynch_Acceptor.cpp Makefile Asynch_Connector.cpp POSIX_Asynch_IO.cpp Asynch_IO.cpp Strategies_T.cpp Asynch_IO_Impl.cpp Svc_Handler.cpp Asynch_Pseudo_Task.cpp WIN32_Asynch_IO.cpp Cached_Connect_Strategy_T.cpp Caching_Strategies_T.cpp
ACE_Demux:该目录包含的是ACE中的Reactor和Proactor框架代码; 包含代码:Dev_Poll_Reactor.cpp Priority_Reactor.cpp TP_Reactor.cpp Event_Handler.cpp Proactor.cpp TkReactor.cpp Event_Handler_T.cpp QtReactor.cpp WFMO_Reactor.cpp FlReactor.cpp Reactor.cpp WIN32_Proactor.cpp Makefile SUN_Proactor.cpp XtReactor.cpp Msg_WFMO_Reactor.cpp Select_Reactor.cpp POSIX_CB_Proactor.cpp Select_Reactor_Base.cpp POSIX_Proactor.cpp Select_Reactor_T.cpp
ACE_IPC:该目录包含的是ACE中进程间通讯的一些封装代码: 包含代码:ATM_Acceptor.cpp Makefile ATM_Addr.cpp Pipe.cpp ATM_Connector.cpp SPIPE.cpp ATM_Params.cpp SPIPE_Acceptor.cpp ATM_QoS.cpp SPIPE_Addr.cpp ATM_Stream.cpp SPIPE_Connector.cpp DEV.cpp SPIPE_Stream.cpp DEV_Addr.cpp SV_Message.cpp DEV_Connector.cpp SV_Message_Queue.cpp DEV_IO.cpp SV_Semaphore_Complex.cpp FIFO.cpp SV_Semaphore_Simple.cpp FIFO_Recv.cpp SV_Shared_Memory.cpp FIFO_Recv_Msg.cpp Signal.cpp FIFO_Send.cpp TLI.cpp FIFO_Send_Msg.cpp TLI_Acceptor.cpp FILE.cpp TLI_Connector.cpp FILE_Addr.cpp TLI_Stream.cpp FILE_Connector.cpp TTY_IO.cpp FILE_IO.cpp Typed_SV_Message.cpp IOStream.cpp Typed_SV_Message_Queue.cpp IOStream_T.cpp UNIX_Addr.cpp IO_SAP.cpp UPIPE_Acceptor.cpp MEM_Acceptor.cpp UPIPE_Connector.cpp MEM_Addr.cpp UPIPE_Stream.cpp MEM_Connector.cpp XTI_ATM_Mcast.cpp MEM_IO.cpp MEM_SAP.cpp MEM_Stream.cpp
ACE_LIB:该目录将包含ACE编译好的各个子库;
ACE_Logging:该目录包含ACE中的日志处理相关代码; 包含代码:Dump.cpp Log_Msg_UNIX_Syslog.cpp Dump_T.cpp Log_Record.cpp Log_Msg.cpp Logging_Strategy.cpp Log_Msg_Backend.cpp Makefile Log_Msg_Callback.cpp Trace.cpp Log_Msg_IPC.cpp Log_Msg_NT_Event_Log.cpp
ACE_Memory:该目录包含了ACE内存处理相关代码; 包含代码:Based_Pointer_Repository.cpp Obstack.cpp Based_Pointer_T.cpp Obstack_T.cpp Makefile PI_Malloc.cpp Malloc.cpp Read_Buffer.cpp Malloc_Allocator.cpp Shared_Memory.cpp Malloc_Instantiations.cpp Shared_Memory_MM.cpp Malloc_T.cpp Shared_Memory_SV.cpp Mem_Map.cpp Memory_Pool.cpp Obchunk.cpp
ACE_Misc:ACE中一些没有明确功能分类的代码,属于杂项; 包含代码:CE_Screen_Output.cpp NT_Service.cpp Makefile gethrtime.cpp
ACE_Nameservices:该目录包含了ACE中名字服务相关代码; 包含代码: Name_Space.cpp Local_Name_Space.cpp Naming_Context.cpp Local_Name_Space_T.cpp Registry_Name_Space.cpp Makefile Remote_Name_Space.cpp Name_Proxy.cpp Name_Request_Reply.cpp
ACE_Sockets:该目录包含的是ACE的socket封装代码; 包含代码:Addr.cpp SOCK_CODgram.cpp INET_Addr.cpp SOCK_Connector.cpp IPC_SAP.cpp SOCK_Dgram.cpp LOCK_SOCK_Acceptor.cpp SOCK_Dgram_Bcast.cpp LSOCK.cpp SOCK_Dgram_Mcast.cpp LSOCK_Acceptor.cpp SOCK_IO.cpp LSOCK_CODgram.cpp SOCK_SEQPACK_Acceptor.cpp LSOCK_Connector.cpp SOCK_SEQPACK_Association.cpp LSOCK_Dgram.cpp SOCK_SEQPACK_Connector.cpp LSOCK_Stream.cpp SOCK_Stream.cpp Makefile Sock_Connect.cpp Multihomed_INET_Addr.cpp SOCK.cpp SOCK_Acceptor.cpp
ACE_Streams:该目录包含了ACE中的Streams和Task框架代码; 包含代码:CDR_Base.cpp Module.cpp CDR_Stream.cpp Multiplexor.cpp Codeset_IBM1047.cpp Reactor_Notification_Strategy.cpp Codeset_Registry.cpp Stream.cpp Codeset_Registry_db.cpp Stream_Modules.cpp IO_Cntl_Msg.cpp Task.cpp Makefile Task_T.cpp Message_Queue.cpp Message_Queue_T.cpp
ACE_Svcconf:该目录包含了ACE中的Service Configurator框架代码; 包含代码:DLL.cpp Service_Types.cpp DLL_Manager.cpp Shared_Object.cpp Dynamic_Service.cpp Svc_Conf.l Dynamic_Service_Base.cpp Svc_Conf.y Makefile Svc_Conf_Lexer_Guard.cpp Parse_Node.cpp Svc_Conf_l.cpp Service_Config.cpp Svc_Conf_y.cpp Service_Manager.cpp XML_Svc_Conf.cpp Service_Object.cpp Service_Repository.cpp Service_Templates.cpp
ACE_Threads:该目录包含了ACE中的线程和同步机制相关代码,例如:thread manager; 包含代码:Activation_Queue.cpp Process_Manager.cpp Thread.cpp Atomic_Op.cpp Process_Mutex.cpp Thread_Adapter.cpp Atomic_Op_T.cpp Process_Semaphore.cpp Thread_Control.cpp File_Lock.cpp RW_Process_Mutex.cpp Thread_Exit.cpp Future.cpp Synch.cpp Thread_Manager.cpp Future_Set.cpp Synch_Options.cpp Token.cpp Makefile Synch_T.cpp Process.cpp Test_and_Set.cpp
ACE_Timer:该目录包含ACE中和时间相关的代码; 包含代码:Timer_Heap.cpp Basic_Stats.cpp Timer_Heap_T.cpp High_Res_Timer.cpp Timer_List.cpp Makefile Timer_List_T.cpp Profile_Timer.cpp Timer_Queue.cpp System_Time.cpp Timer_Queue_Adapters.cpp Time_Request_Reply.cpp Timer_Queue_T.cpp Timeprobe.cpp Timer_Wheel.cpp Timeprobe_T.cpp Timer_Wheel_T.cpp Timer_Hash.cpp Timer_Hash_T.cpp
ACE_Token:Token是ACE中实现的一种同步机制,保证严格的FIFO或LIFO策略来获得锁。ACE通过Token机制实现了分布式同步机制。 包含代码:Local_Tokens.cpp Token_Collection.cpp Token_Request_Reply.cpp Makefile Token_Invariants.cpp Remote_Tokens.cpp Token_Manager.cpp
ACE_Utils:ACE中的一些基础数据结构和算法的工具类代码; 包含代码:ACE.cpp Init_ACE.cpp Active_Map_Manager.cpp Intrusive_List.cpp Active_Map_Manager_T.cpp Intrusive_List_Node.cpp Arg_Shifter.cpp Lib_Find.cpp Array_Base.cpp Makefile Auto_IncDec_T.cpp Managed_Object.cpp Auto_Ptr.cpp Map.cpp Cache_Map_Manager_T.cpp Map_Manager.cpp Caching_Utility_T.cpp Map_T.cpp Capabilities.cpp Message_Block.cpp Cleanup_Strategies_T.cpp Message_Block_T.cpp Configuration.cpp Method_Request.cpp Configuration_Import_Export.cpp Node.cpp Connection_Recycling_Strategy.cpp Notification_Strategy.cpp Containers.cpp Object_Manager.cpp Containers_T.cpp Pair.cpp Date_Time.cpp Pair_T.cpp Dirent.cpp RB_Tree.cpp Dirent_Selector.cpp Recyclable.cpp Dynamic.cpp Refcountable.cpp Filecache.cpp Registry.cpp Flag_Manip.cpp SString.cpp Framework_Component.cpp Sample_History.cpp Framework_Component_T.cpp Singleton.cpp Free_List.cpp Stats.cpp Functor.cpp String_Base.cpp Functor_T.cpp String_Base_Const.cpp Get_Opt.cpp Swap.cpp Handle_Ops.cpp Unbounded_Queue.cpp Hash_Cache_Map_Manager_T.cpp Unbounded_Set.cpp Hash_Map_Manager.cpp Unbounded_Set_Ex.cpp Hash_Map_Manager_T.cpp Vector_T.cpp Hash_Map_With_Allocator_T.cpp Hashable.cpp
include:该目录又包含子目录ace,也就是说include/ace/目录下,包含了ACE的所有头文件和.i文件,之所以这样组织,是因为ACE中的源 文件和头文件的包含文件的方式为:#include "ace/OS.h",所以采用这种目录结构方式来存放头文件和.i文件。这里,对头文件和.i 文件,没有进一步按照功能划分,就是因为#include "ace/OS.h"这种包含方式,如果头文件和.i文件也按照功能划分,那么代码修改 量相当大;
通过上面给出的目录结构和源文件功能划分及头文件组织方式,相信读者以可以自行对ACE代码进行整理了。在实际整理和编译代码的过程中,需要修改Makefile和ACE头文件中以_T方式为后缀的头文件,例如:Obstack_T.h,需要修改里面模板源文件包含路径。我将在下一篇文章中进行描述。
我再次强调,上面ACE源码划分方式,不一定十分正确^_^,随着我们ACE学习和理解的深入,我们可能会进行更改。其实,在我们整理ACE源文件的时候,我们可以进一步了解ACE的各个源文件大致功能,对我们以后更深入的学习大有裨益。
***********************************************************************************************************************************
在ACE的源代码目录里,有源文件.cpp、头文件.h,我们还发现有以.i和.inl为扩展名的文件。其实,以.i和.inl为扩展名的文件是ACE源码中inline函数的存放形式。
在说明ACE中为什么采用这种方式来存放inline函数之前,我们来说一下inline关键字是什么意识。我们知道当调用一个函数的时候,涉及到返回地址和参数压栈等一些操作,这些操作是函数调用本身的开销。在原来的C代码中,通常采用宏定义的方式模拟函数,来消除函数调用的开销,因此我们知道宏是在预编译时候进行处理的。但是,宏定义本身也有很多缺陷,很容易造成错误的使用。这就是inline关键字诞生的原因。用inline关键字定义的函数,在编译的时候,并不会产生真正的函数,而是在该函数调用处直接展开代码,这样就消除了函数调用的开销。注意,inline关键字,只是给编译器的一个暗示,是不是真的进行了inline处理,是由编译器决定的。
那为什么ACE会采用这样一个特殊的方式来存放inline函呢?我们结合实例给出答案。 我们看一下,Reactor.h文件的结尾处,有如下的处理: #if defined (__ACE_INLINE__) #include "ace/Reactor.i" #endif /* __ACE_INLINE__ */
在看一下Reactor.cpp文件开头处的宏处理: #if !defined (__ACE_INLINE__) #include "ace/Reactor.i" #endif /* __ACE_INLINE__ */
上面的Reactor.h,Reactor.cpp和Reactor.i文件是ACE的Reactor框架的相关代码。上面的宏定义我们很好理解,在头文件中的处理为:如果定义了宏__ACE_INLINE__,那么我们就把Reactor.i文件include到头文件中。在源文件中处理为:如果没有定义宏__ACE_INLINE__,那么就把Reactor.i文件include到源文件中。其实有了上面inline含义的介绍,我们不难理解为什么采用这种方式来进行处理。这里我们假设定义了宏__ACE_INLINE__,并且Reactor.i文件是被include到源文件里,而不是被include头文件里,那么会产生什么后果那?我们知道inline函数,在编译器编译后,是不会产生真正的函数的,因此,如果有其它源文件,例如zhx.cpp,调用了Reactor.i文件中的inline函数,那么在连接的时候,就会抛出符号无法解析的错误,而如果Reactor.i文件是被include到了头文件中,并且我们在zhx.cpp中有调用Reactor.i文件中的函数,那么在zhx.cpp中,只需要包含Reactor.h头文件即可,则Reactor.i的相关inline函数在zhx.cpp也进行了代码展开处理。如果没有定义宏__ACE_INLINE__,则Reactor.i被include到源文件中,没有任何问题,因为Reactor.i中的函数在编译后,会产生真正的函数,而不是被inline处理。这就是ACE为什么采用这样的方式进行处理的原因。
在上面的介绍中,我们同时也发现了inline的缺点,就是它会造成代码的膨胀。因此,不是什么样的函数都适合用inline来定义,只有那些短小的函数才适合采用inline处理。
注:ACE为什么会采用.i和.inl两种扩展名形式的文件来存放inline函数,我还不是很清楚,但感觉以.inl形式存放的文件是早期ACE代码中的方式,后期的ACE代码采用.i方式来存放inline函数,也就是说这应该是一个历史遗留问题^_^,开源项目的缺点。 |