关于ACE

2 views
Skip to first unread message

lihongt...@gmail.com

unread,
Dec 13, 2006, 2:21:13 AM12/13/06
to 李洪涛的论坛
正在做的项目在用ACE做网络引擎,因此买了2本ACE的书(《C++网络编程卷1》《ACE程序员指南》),看了下ACE的,这里记下一点心得备忘。

ACE的全称是自适应通信环境(ADAPTIVE Communication
Environment),ADAPTIVE又是 A Dynamically Assembled Protocol
Transformation, Integration, and eValuation Environment
的缩写。历史悠久,甚至比GNU还久远。

ACE大量运用设计模式,很好的包装的网络通信的全部细节,消弭各种操作系统之间的差异,也提供了完整的接口保证足够的灵活性,并且大量运用模板等C++的高级特性,保证了效率(通用的东西往往效率低,ACE是否的确没有比原生代码损失效率这个有待进一步证实)。

ACE提供的全部的源代码,可以在各种平台下编译。

ACE中最主要的几个东西:
1。Reactor
反应式多路分离器,向它注册一些事件及相应的Handler,当事件发生时它会调用相应的Handler,这个比较容易理解也比较容易使用。就好像Select然后根据不同的事件调用不同的函数。其本质是Reactor告诉你何时可做何事,接下来你执行操作。

2。Proactor前摄式多路分离器,异步I/O模式,用法是发起一个操作,等操作完成了Proactor告诉你。Windows下的完成端口就是这样一种模式,事实上ACE在Windows上实现的Proactor就是用的完成端口。这个看得比较少,目前还没有详细了解。

3。Task
这个东西很难用一个明确的中文来准确完整的表达,它封装了线程和线程池,完全隔离了各平台原生线程的差异,有一个svc函数,相当于原生线程里面的线程函数。

4。Message_Block,消息块,包含一个数据块和一个计数的指针引用,合理使用既能很好的封装数据又能方便使用,还能避免不必要的数据拷贝。

5。MessageQueue,消息队列,提供了一个线程安全的消息队列

6。ACE_OS里面提供了不少有用的函数和宏,掩盖系统之间的差异。
例如ACE_DEBUG提供了类似于MFC中的TRACE的功能
ACE_OS::gettimeofday()返回当前时间,类似于linux中的gettimeofday()和windows下的gettickcount()

lihongt...@gmail.com

unread,
Dec 20, 2006, 10:08:17 PM12/20/06
to 李洪涛的论坛
ACE的TP_Reactor的特性:一个事件处理器只会在一个线程中出现。
就是说如果给每个连接做一个事件处理器,那么这个连接的读写如果阻塞,它自己的后续时间将会被阻塞,但是不会影响到其他的连接。因为AcceptHandler只有一个,如果AcceptHandler被阻塞,则后面的连接请求将不会被处理。

坛主

unread,
Dec 26, 2006, 4:55:23 AM12/26/06
to 李洪涛的精神垃圾桶和实用工具箱
之前一直都是在自己的学习项目中使用ACE,入口函数都使用的ACE_TMAIN(),没有去深究这个宏到底做了什么,今天终于吃了大亏。当我把做好的网络底层加入别人做好的程序中时,编译没有任何问题,一旦运行起来到调用ACE_SOCK_Connector的connect()函数就会触发异常,当在ntdll.dll中,对应的最后调用代码是ACE_OS::thread_mutex_lock里面的::EnterCriticalSection
(m);郁闷啊,折腾了半天,经别人提醒才知道没有调用ACE::init();
估计ACE_TMAIN里面就是干了这个事情。日,我恨宏!

坛主

unread,
Jan 19, 2007, 4:20:52 AM1/19/07
to 李洪涛的精神垃圾桶和实用工具箱
ace/OS_NS_Thread.inl(3602) : error C2039: 'TryEnterCriticalSection' :
is not a member of '`global namespace''
ace/OS_NS_Thread.inl(3602) : error C3861: 'TryEnterCriticalSection':
identifier not found

这个编译错误是因为 _WIN32_WINNT
这个宏的值设置得过低了,
可以在编译选项中的预处理器定义中加入_WIN32_WINNT=0x0500

其实在使用ACE的时候总是先包含ACE的头文件就不会出现这个问题了。
另外如果项目有预编译头文件,不妨把ACE的头文件放到stdafx.h中

坛主

unread,
Feb 8, 2007, 5:20:59 AM2/8/07
to 李洪涛的精神垃圾桶和实用工具箱
在使用TP_Reactor时
如果登记的处理器比线程池的线程数多时,可能出现事件触发却无线程可用的尴尬局面。
为此需要保证每个事件处理器处理事件都能及时返回。

recv和accept问题不大,可操作才会去操作,不会阻塞
send则可能陷入阻塞,因此可以设置一个超时。

另一个方案是对可用的线程数计数,当可用的线程数量少到一定程度时,
做一些调整(添加新的线程或者减短超时)。
这个计数需要是线程安全的,如果代价太大就不值得了
幸运的是 在大多数机器体系结构上,对基本类型的改变都是原子的。(参见 《ACE 程序员指南》p227)

坛主

unread,
Feb 14, 2007, 4:53:05 AM2/14/07
to 李洪涛的精神垃圾桶和实用工具箱
另外可以让ACE_SOCK_Stream工作在非阻塞模式,只需要在send返回-1的时候检查下errno是否为
EWOULDBLOCK即可

我们可以对Reactor通知事件,ACE_Reactor::instance()->notify( handler, mask)
ACE有一个类包装了这个这种调用 ACE_Reactor_Notification_Strategy
另外ACE_Message_Queue自带一个通知对象指针,可以为它指定一个上面的对象
则在有ACE_Message_Block进入ACE_Message_Queue时,会自动调用notify
发起反应器的事件。这种方法用在发送数据上非常方便。

Reply all
Reply to author
Forward
0 new messages