﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-CppExplore</title><link>http://www.cppblog.com/CppExplore/</link><description>一切像雾像雨又像风</description><language>zh-cn</language><lastBuildDate>Wed, 15 Apr 2026 03:49:05 GMT</lastBuildDate><pubDate>Wed, 15 Apr 2026 03:49:05 GMT</pubDate><ttl>60</ttl><item><title>【原创】sBPM产品介绍 </title><link>http://www.cppblog.com/CppExplore/archive/2013/08/20/202668.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Tue, 20 Aug 2013 06:18:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2013/08/20/202668.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/202668.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2013/08/20/202668.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/202668.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/202668.html</trackback:ping><description><![CDATA[作者：CppExplore &nbsp;<a href="http://www.cppblog.com/CppExplore/"><u><font color="#800080">http://www.cppblog.com/CppExplore/</font></u></a>和<a href="http://blog.csdn.net/cppexplore"><font color="#000080">http://blog.csdn.net/cppexplore</font></a>同步发布。<br />近3年没发文章，谨以本文总结我和团队兄弟们3年在业务之外的工作成果。<br /><br /><span style="font-family: Arial; font-size: 14pt">&nbsp;</span><strong><span style="font-family: Arial; font-size: 14pt">1 </span></strong><strong><span style="font-family: Arial; font-size: 14pt">产品目标</span></strong><strong><span style="font-family: '微软雅黑','sans-serif'; font-size: 16pt"></span></strong>&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 125%; font-family: Arial; font-size: 12pt">降低高性能服务领域开发门槛，提高开发效率，同时解决测试、运维、监控、数据分析中的各类问题。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">围绕此目标，sBPM（snda Business Process Management:盛大业务流程管理）将流程管理概念延伸到高性能服务器领域，使用SOA服务编排配置方式进行服务开发与组装，提供外围支持工具，封装监控、告警、日志类基础功能。</span> 
<h1><strong><span style="font-family: Arial; font-size: 14pt">2 </span></strong><strong><span style="font-family: Arial; font-size: 14pt">产品功能</span></strong><strong></strong></h1>
<p><span style="font-family: Arial; font-size: 12pt">1</span><span style="font-family: Arial; font-size: 12pt">）支持SOA服务路由</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">2</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">）支持SOA服务编排：对多个服务进行调用流程编排</span></p>
<p style="line-height: 125%; text-indent: -21pt; margin: 0cm 0cm 0pt 21pt"><span style="line-height: 125%; font-family: Arial">&#216;&nbsp;</span><span style="line-height: 125%; font-family: Arial">通过sBPEL语法（xml风格）描述业务流程</span></p>
<p style="line-height: 125%; text-indent: -21pt; margin: 0cm 0cm 0pt 21pt"><span style="line-height: 125%; font-family: Arial">&#216;&nbsp;</span><span style="line-height: 125%; font-family: Arial">编排流程支持：并行调用、串行调用、跳转流程，支持根据服务任意返回值、流程内变量等进行跳转或赋值操作。</span></p>
<p style="line-height: 125%; text-indent: -21pt; margin: 0cm 0cm 0pt 21pt"><span style="line-height: 125%; font-family: Arial">&#216;&nbsp;</span><span style="line-height: 125%; font-family: Arial">支持对编排结果嵌套编排</span></p>
<p style="line-height: 125%; text-indent: -21pt; margin: 0cm 0cm 0pt 21pt"><span style="line-height: 125%; font-family: Arial">&#216;&nbsp;</span><span style="line-height: 125%; font-family: Arial">编排目标原生支持sBPM自定义二进制协议，通过外部适配支持对HTTP协议以及其他协议进行编排。</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">3</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">）支持服务编排语法进行服务开发</span></p>
<p style="line-height: 125%; text-indent: -21pt; margin: 0cm 0cm 0pt 21pt"><span style="line-height: 125%; font-family: Arial">&#216;&nbsp;</span><span style="line-height: 125%; font-family: Arial">通过异步插件机制可任意扩展编排目标，已支持：本地内存、memcache、redis、mysql、oracle，且针对各数据源特点不同分别支持一致性hash、分库分表等策略。通过对基础存储进行编排达到服务开发的目的</span></p>
<p style="line-height: 125%; text-indent: -21pt; margin: 0cm 0cm 0pt 21pt"><span style="line-height: 125%; font-family: Arial">&#216;&nbsp;</span><span style="line-height: 125%; font-family: Arial">通过同步插件机制可任意扩展流程内编排逻辑，已支持大量常用逻辑插件。</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">4</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">）提供BPEL4WS语法向sBPEL语法转换工具，可使用BPEL4WS可视化流程编排工具进行编排</span></p>
<p style="line-height: 125%; text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">5）</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">提供配置接口、明细日志、性能数据接口、业务量数据接口、告警接口等支持。尤其对实时日志分析提供特别支持。</span></p>
<p style="line-height: 125%; text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">6）</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">对编排结果接口，提供HTTP/TCP两类通用授权网关对外暴露。提供TCP接口的同步、异步IPC调用。</span></p>
<p style="line-height: 125%; text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">7）</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">对编排结果接口，提供可视化测试用例编辑器以及自动化运行器。</span></p>
<h1><strong><span style="font-family: Arial; font-size: 14pt">3 </span></strong><strong><span style="font-family: Arial; font-size: 14pt">类似产品比较</span></strong><strong></strong></h1>
<p style="line-height: 125%; text-indent: 21pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">在后端服务器领域，没有类似支持SOA服务编排的产品，其他领域产品存在部分类似点，比较如下：</span></p>
<p style="line-height: 125%; text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">1)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp; </span></span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">sBPM</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">与ESB比较</span></p>
<p style="line-height: 125%; text-indent: 18pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">ESB</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">是对已存在的复杂异构环境的黏合剂，主要强调消息路由、协议适配。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">sBPM</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">拥有完善产品线，虽有扩展机制支持组合已有系统，但更侧重于从无到有开发全新系统；sBPM虽支持消息路由功能，但更强调服务编排功能。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">通过ESB的协议适配机制可以大大加强sBPM的编排能力，可作为sBPM的补充。</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">2</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">）sBPM与BPEL4WS类产品、jBPM比较</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BPEL4WS</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">使用XML语法描述业务流程，由BEA、IBM和Microsoft编写和公布，是针对WEB服务的SOA组合编排，代表产品众多，不详举。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">sBPM</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">使用sBPEL描述业务流程，提供BPEL4WS语法向本语法翻译工具，可复用BPEL4WS的可视化流程开发工具，与BPEL4WS定位于WEB服务编排不同，sBPM侧重于高性能后端服务，通过内置插件以及扩展服务不限编排组合对象，可以是基础服务、cache、本地内存、redis、mysql、oracle、http接口等。<br /></span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jBPM</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">使用自定义jpdl描述业务流程，提供可视化流程编辑器、调试器，定位为信息化、工作流领域，不强调编排目标与性能，更重视流程数据持久化、与人交互流程。<br /></p>
<p style="line-height: 125%; text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">3)<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp; </span></span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">sBPM</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">与Node.js比较<br /></span><span style="font-family: Arial">Node.js</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">相对前两着，和sBPM更为接近。它定位为快速构建异步高性能服务后端，和传统web容器相同，仅支持单线程。它强调IO异步，以类似网络proactor模型设置回调方式进行开发，使用javascript语言进行开发，容易获得已有前端人员认可，同时也带来了不可避免的调式工作。</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sBPM</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">和node.js同样定位为快速构建异步高性能服务后端，强调运行时异步性能，默认线程和CPU数量相同。和node.js不同，sBPM不需开发，以同步方式来描述异步流程，配置思路符合业务思维，配合级联部署、层层组合较容易组装产生平台级的强大服务。sBPM属完整产品，对接口日志、各接口业务量、依赖接口业务量、接口耗时、各依赖耗时、告警分布做了统一封装。</span></p>
<p style="line-height: 125%"><span style="line-height: 125%; font-family: Arial; font-size: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Node.js</span><span style="line-height: 125%; font-family: Arial; font-size: 12pt">目标人群仍旧是开发人员。而sBPM框架不再需要传统开发、代码调试角色。在云计算时代，我相信sBPM是云平台发展的必然趋势，传统后端开发角色终将被合架构师、开发角色、业务运维角色为一体的业务配置角色所替代。</span></span></p>
<h1><strong><span style="font-family: Arial; font-size: 14pt">4 </span></strong><strong><span style="font-family: Arial; font-size: 14pt">产品优点</span></strong><strong></strong></h1>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="font-family: Arial">1）&nbsp;</span><span style="font-family: Arial; font-size: 12pt">产品线完善：覆盖编排运行容器、可视化编排工具、可视化测试工具、运营支撑平台等。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="font-family: Arial">2）&nbsp;</span><span style="font-family: Arial; font-size: 12pt">缩短产品开发时间：基于sBPM产品开发新产品，完全配置方式，颠覆传统开发方式，将产品研发时间完全缩短到产品需求提炼过程。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="font-family: Arial">3）&nbsp;</span><span style="font-family: Arial; font-size: 12pt">提高产品质量：开发过程不会引入bug，节省测试成本。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="font-family: Arial">4）&nbsp;</span><span style="font-family: Arial; font-size: 12pt">产品高可扩展、可维护：流程配置完全贴近业务本质，保护流程投资。流程编排方式更容易产生更强大、功能更完善的产品，维护更直接简单。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="font-family: Arial">5）&nbsp;</span><span style="font-family: Arial; font-size: 12pt">高性能：sBPM将性能与稳定性做为本产品第一竞争力，容器在初始化阶段解析流程文件到内存结构，运行中采用全异步机制。基于sBPM配置产生的产品天生具有高性能，高于手写方式。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span style="font-family: Arial">6）&nbsp;</span><span style="font-family: Arial; font-size: 12pt">可运营性：sBPM产品融合我方实际运营经验，关注配置、告警、性能、日志、安全等方面。</span></p>
<h1><strong><span style="font-family: Arial; font-size: 14pt">5 </span></strong><strong><span style="font-family: Arial; font-size: 14pt">产品使用情况</span></strong><strong></strong></h1>
<p style="text-indent: 24pt"><span style="font-family: Arial; font-size: 12pt">通过近3年持续发展与推广，sBPM已在盛大基础平台内广泛使用，涵盖认证、注册、用户信息、计费、安全等业务。目前sBPM产品已管理过10T关系型数据库、几十亿记录，涵oracle、mysql、hbase、memcache、redis多种数据源，每日外部请求量近10亿次，内部组合调用过30亿次。</span></p>
<h1><strong><span style="font-family: Arial; font-size: 14pt">6 </span></strong><strong><span style="font-family: Arial; font-size: 14pt">产品展望</span></strong><strong></strong></h1>
<p style="text-indent: -35.25pt; margin: 0cm 0cm 0pt 35.25pt"><span style="font-family: Arial; font-size: 12pt">1）</span><span style="font-family: Arial; font-size: 12pt">将sBPM独立产品化，与内部运营支撑系统藕荷部分重构为插件接口，裁减掉不适合产品化部分。</span></p><span style="font-family: Arial; font-size: 12pt">2）将sBPM和私有云概念结合，搭建PAAS平台，对外提供运营服务。</span><br /><img src ="http://www.cppblog.com/CppExplore/aggbug/202668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2013-08-20 14:18 <a href="http://www.cppblog.com/CppExplore/archive/2013/08/20/202668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】高性能服务器本质论 </title><link>http://www.cppblog.com/CppExplore/archive/2010/12/19/136951.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Sun, 19 Dec 2010 09:45:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2010/12/19/136951.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/136951.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2010/12/19/136951.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/136951.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/136951.html</trackback:ping><description><![CDATA[<p>作者：CppExplore &nbsp;<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a>和<a href="http://blog.csdn.net/cppexplore"><font color=#000080>http://blog.csdn.net/cppexplore</font></a>同步发布<br><strong>一 服务器分类<br></strong>从软件性能角度，高性能服务器分：cpu密集型服务器/IO密集型服务器<br><span style="COLOR: red">(1)CPU密集型</span><span style="COLOR: red">：该类服务器没有对io的访问/没有同步点，性能瓶颈在于对cpu的充分利用</span>。<br>典型的如转发服务器/代理服务器/协议转换类服务器/分布式总线服务器等。<br><span style="COLOR: red">(2)IO密集</span><span style="COLOR: red">型：该类服务器存在对cache/db/硬盘等的同步访问，或者对fcgi/其他服务器等的同步访问</span>。<br>简单说有同步访问点的均归属此类服务器。当前硬件基础下，有同步操作的服务器，性能瓶颈均在同步点的返回快慢上，而非cpu。<br><strong>二&nbsp;网络层机制<br></strong>对上述两类服务器，均需要同样高效的网络层机制。当前高效的网络层也就是大家熟知的iocp/epoll/kqueue/port/dev.poll等，在各个os下使用宿主os推荐的高效网络层机制，任何通过其他机制绕过这些机制的做法都不可能达到最好性能。这里推荐下boost.asio，文档齐全，示例丰富，学习曲线平缓。<br><strong>三&nbsp;CPU密集型服务器设计<br></strong><span style="COLOR: red">（1）单进程单线程是改类服务器的本质特征。<br></span>整个进程只存在一个线程，所有代码均运行在同一个线程中，均顺序执行，任何地方不需要加锁。由于网络线程的存在，实际上该类程序的唯一线程就是网络线程，以linux为例，就是epoll线程。<br>在多核情况下，fork和cpu个数相同的进程数并且如果可能使用sched_setaffinity类函数将进程和cpu绑定。以充分利用多核性能。<br>该类服务器的代表：tuxedo/nginx.<br><span style="COLOR: red">（2）单进程多线程，但多线程均完成同样的功能，彼此之间互不依赖/互不影响 ，这是该类服务器的变体。<br></span>单进程单线程无疑是该类服务器最理想最完美的实现。但有时候为了简化部署，简化业务上报，业务自检，统一日志,尤其是统计类日志/配置动态生效等附加功能考虑，不得已牺牲少许性能而将上述&#8220;单进程单线程，fork多个充分利用多核&#8221;方案改造为&#8220;独立多线程充分利用多核&#8221;方案。<br>该方案中，多线程中的各个线程仍然是顺序执行，任何地方不需要加锁，均为独立的网络线程。<br>相对方案(1)， 该方案编程更复杂，而linux下线程调度又不如进程高效，整体看为方便性牺牲了少许性能。<br>该类服务器的代表：我们的协议转换网关/分布式总线服务器等。<br><span style="COLOR: red">（3）高效算法<br></span>优化耗时较多算法/挑选合适容器，完成固定任务，尽量减少cpu的运算量。<br><span style="COLOR: red">（4）错误设计：区分网络线程/业务线程，将业务线程根据业务特点划分各个线程阶段。<br></span>对cpu密集型的服务器来说，关键在于充分利用cpu，尽量减少无用代码的执行。引如中间处理线程，意味着引入锁切换/内存复制/更多无效代码，不可否认，在已有协议栈情况下，根据业务特点化分线程可以简化编程。单纯的单一线程意味着更复杂的编码，尤其是涉及到更多中间状态时。<br>在该场景下，有位牛人，对线程的点评：&#8220;<span style="COLOR: red">线程是给那些不能将程序执行序转换成状态机的笨人用的</span>&#8221; 这句话真是再合适不过了。<br><strong>四 IO密集型服务器设计<br></strong>(1)网络层多线程，中间线程按照业务特点设定，同步点操作使用多线程<br><span style="COLOR: red">同步点使用多线程是该类服务器的本质特征。</span>在同步操作的返回时间不能由本服务器控制的前提下，本服务器所能做的也就只能是加多线程数，提供同步并发数。线程数的最优配置取决于网络层入口并发数以及同步操作返回的时间。简单划分可以网络线程数=cpu个数/2.同步点线程数还取决于同步操作的代价，若为廉价的cache操作，则可适当增多，若为昂贵的db操作，则要根据可以分配的连接数决定。<br>(2)减少人为产生的同步点<br>尽量减少访问其他系统使用同步接口。<br>(3)优化同步点<br>根据同步操作的特点优化: 异步/增大缓存/批量等。<br><br><strong>五&nbsp;内存操作/锁机制/内核态用户态切换/日志操作<br></strong>(1)内存操作<br>内存申请：减少内存动态分配，推荐tcmalloc<br>内存复制：CPU密集型，必须的内存复制：(a)网络读：处从内核态复制到用户态，仅1次 (b)网络写：异步内存复制/用户态到内核态 ，仅2次<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IO密集型，内存复制非关键点。<br>(2)锁机制 CPU密集型：尽量无锁. IO密集型: 非关键点<br>(3)内核态用户态切换<br>两类服务器均相同，尽量减少内核态/用户态互相切换：每次调用系统调用尽可能读取更多字符/仅可能减少不必要的系统调用（去除不必要的调用/通过缓存机制减少调用次数）。<br>(4)日志操作 略<br><strong>六&nbsp;进程vs线程vs协程<br></strong>进程和线程（略）<br><span style="COLOR: red">协程：和进程/线程这种cpu调度单元不同，它更多是线程内对象之间一种调度理念的优化。</span>协程对象有自己的堆栈，可以通过直接跳转直接转换执行点，减少了内存寻址操作。它特别适合用来优化线程内的某些基础组件，包括：状态机/调停者模式（或者线程内队列）。</p>
<p>在CPU密集型服务器的设计中，说道&#8220;线程是给那些不能将程序执行序转换成状态机的笨人用的&#8221;，而有了协程，我们有了一种新的简化编程的方法。将协程用于网络层，可以手动实现类似select的功能，用于多对象参与的复杂中间状态，可以简化编程。<br><span style="COLOR: red">但从整体性能角度看，协程则是鸡肋的存在</span>，从几年前出现boost.Coroutine，到现在该项目停止开发，boost引入更多其他方案asio/mpl/statechart，协程一路蹒跚。<br><strong>七&nbsp;总结<br></strong>在当前硬件体系架构下，服务器性能的关键仍然是传统的cpu/io/memory.<br>cpu密集型的服务器，需要最大限度充分利用所有cpu，以及尽量少的进行内存申请/内存复制。<br>IO密集型服务器，需要最大限度提高io能力，为达到该目的，可以在非同步线程牺牲对cpu的利用率/牺牲对memory的高效使用，一切为提高io并发能力服务。<br><strong>八 &nbsp;后记<br></strong>特别感谢张杰同学代替我编译探测程序代码，让我有时间码点文字。</p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/136951.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2010-12-19 17:45 <a href="http://www.cppblog.com/CppExplore/archive/2010/12/19/136951.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】从同步互斥机制到智能指针使用成本 </title><link>http://www.cppblog.com/CppExplore/archive/2010/08/28/125067.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Sat, 28 Aug 2010 10:22:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2010/08/28/125067.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/125067.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2010/08/28/125067.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/125067.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/125067.html</trackback:ping><description><![CDATA[<p>作者：CppExplore &nbsp;<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a>和<a href="http://blog.csdn.net/cppexplore"><font color=#000080>http://blog.csdn.net/cppexplore</font></a>同步发布<br><br>一 semaphore机制<br>古老的信号量机制，80年代初，从System V体系中产生，称为System v信号量。90年代，Posix标准确立，其中的信号量称为posix信号量。当前linux系统支持这两种信号量（man semget/ man sem_post)。System v信号量为有名信号量，可以用于多进程间的互斥同步。posix信号量分有名和无名两种，当前linux只支持无名信号量，可以用于多线程之间的互斥同步，通过共享内存也可以用于多进程之间。<br>信号量属于内核级别的互斥同步机制，相关调用总是陷入内核态，属于功能强大/重量级的实现。<br><br>二 spinlock机制<br>多核SMP的cpu流行后，出现的新的互斥同步机制。spinlock实现原理为用户态循环尝试机制，不陷入内核态进行线程切换。spinlock的原子性通过CAS(CompareAndSwap)原语实现。使用spinlock时，应该保证保护区间内代码执行迅速，不应该存在io等耗时操作。<br>多核系统下，针对可快速执行的保护区使用用户态循环尝试机制，可以保证执行线程不需要引起上下文切换即可快速执行通过，这种机制也被形象的称为lock-free机制。我们可以这样理解：lock-free机制即为循环尝试，spinlock是它的具体实现。<br><br>spinlock的实现有多种，常见的有pthread_spin_lock，该spinlock无限制循环尝试，在多核环境下并且保护区代码执行迅速时，执行线程很快可以拿到锁，但当单核环境或者保护区代码执行慢速时，则会耗尽该线程拥有的时间片之后交出cpu，造成cpu的浪费。另一常见的spinlock是boost智能指针中的实现，进行3次无间断的循环CAS原语判断，之后若再次失败，则调用sleep族函数，交出cpu执行权，待再次分配到cpu时间片后继续进行CAS原语判断操作。<br></p>
<p><br><span style="FONT-SIZE: 14pt">三 mutex机制</span><br>mutex属于os之上的再次封装实现。在linux2.6内核上，线程库为nptl，其中的mutex基于futex机制实现，它的实现原理，简单说就是spinlock+semaphore，首先使用spinlock尝试，可以拿到锁则直接向下执行，拿不到锁则执行semaphore机制，陷入内核态，进入线程切换。<br>在多核环境下，当mutex保护的代码段内无io操作，执行很快时，大多数情况下通过spinlock都可拿到锁，不需要陷入内核态。</p>
<p><br><span style="FONT-SIZE: 14pt">四 为智能指针正名(boost)</span><br>智能指针的引用计数仅仅为一个整型变量的增减，属于执行迅速的典型，使用spinlock机制保护，最新boost版本中仅仅是spinlock，而非mutex。从性能角度说，使用智能指针的现象是cpu略微上升（循环尝试导致），而并发量/单个请求的响应时间并无明显影响。proactor机制实现的网络层，智能指针基本无法绕过，刻意避免带来的只能是丑陋的代码和维护量的上升。但线程之间尽量避免传递指针（智能指针），通过传递id等代替。<br>智能指针有它使用的场景，不能滥用，也不能刻意避免。</p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/125067.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2010-08-28 18:22 <a href="http://www.cppblog.com/CppExplore/archive/2010/08/28/125067.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】单元测试分享 </title><link>http://www.cppblog.com/CppExplore/archive/2010/06/28/118850.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Mon, 28 Jun 2010 01:15:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2010/06/28/118850.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/118850.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2010/06/28/118850.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/118850.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/118850.html</trackback:ping><description><![CDATA[作者：CppExplore &nbsp;<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a>和<a href="http://blog.csdn.net/cppexplore"><font color=#000080>http://blog.csdn.net/cppexplore</font></a>同步发布<br>&nbsp;
<h1><a name=_Toc248746753><span><span>1 </span></span><span>单元测试对象概述</span></a></h1>
<p><span>各个对象组织结构如下：</span></p>
<p>&nbsp;<img height=267 alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/test.JPG" width=605 border=0></p>
<p>&nbsp;</p>
<p><span>职责简述如下：</span></p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td width=111>
            <p align=center><span>对象</span></p>
            </td>
            <td width=508>
            <p align=center><span>职责</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p><span>TestAssert</span></p>
            </td>
            <td vAlign=top width=508>
            <p><span>测试断言：判定测试结果是否正确，一般类似断言表达。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p><span>TestCase</span></p>
            </td>
            <td vAlign=top width=508>
            <p><span>测试用例：多个测试断言组成一个测试用例。测试对象为一个类中的一个具体方法。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p><span>TestSuite</span></p>
            </td>
            <td vAlign=top width=508>
            <p><span>测试套件：多个测试用例组成一个测试套件。测试对象为一个类。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p><span>MainTestSuite</span></p>
            </td>
            <td vAlign=top width=508>
            <p><span>主测试套件：单元测试运行主程序入口。测试用例也可绕过测试套件，直接包含在主测试套件中。</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=111>
            <p><span>TestFixture</span></p>
            </td>
            <td vAlign=top width=508>
            <p><span>测试夹具：用于测试前的初始化操作以及测试后的清理操作，一般包括准备测试的前置条件</span><span>/</span><span>测试对象的状态设置等。</span></p>
            </td>
        </tr>
    </tbody>
</table>
<br>&nbsp;
<h1>2<a name=_Toc248746754><span><span>&nbsp;</span></span><span>单元测试框架选型</span></a></h1>
<p><span>当前存在很多流行的单元测试框架：衍生自</span><span>JUnit</span><span>的</span><span>CppUnit</span><span>，以及简化版本的</span><span>CppUnitLite</span><span>，</span><span>Boost.Test</span><span>测试框架，</span><span>Google Test</span><span>测试框架等。每个测试框架都很完善，都可胜任单元测试任务。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>从使用简单性考虑，依次是</span><span>Boost.Test&gt;&gt;Google Test&gt;&gt;CppUnitLite&gt;&gt;CppUnit.</span></p>
<p><span>本文选择</span><span>Boost.Test</span><span>的单元测试框架讲解。对</span><span>Google Test</span><span>感兴趣的可参看</span><span><a href="http://www.cnblogs.com/coderzh/archive/2009/03/31/1426758.html">http://www.cnblogs.com/coderzh/archive/2009/03/31/1426758.html</a></span><span>。<br>&nbsp; </p>
<h1><a name=_Toc248746755><span><span>3&nbsp;</span></span><span>Boost.Test UTF(Unit Test Framework)</span></a></h1>
<h2><a style="COLOR: #000000" name=_Toc248746756><span><span>3.1 </span></span><span>LogLevel</span></a></h2>
<p><span>讲解</span><span>TestAssert</span><span>前，先说下</span><span>Boost</span><span>测试框架的日志级别，有以下</span><span>9</span><span>个级别：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 border=1>
    <tbody>
        <tr>
            <td width=121>
            <p align=center><span>级别名称</span></p>
            </td>
            <td width=498>
            <p align=center><span>说明</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><span>all / success</span></p>
            </td>
            <td vAlign=top width=498>
            <p><span>报告包括成功测试通知的所有日志信息</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><span>test_suite</span></p>
            </td>
            <td vAlign=top width=498>
            <p><span>显示测试套件信息</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><span>message</span></p>
            </td>
            <td vAlign=top width=498>
            <p><span>显示用户信息</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><strong><span>warning</span></strong></p>
            </td>
            <td vAlign=top width=498>
            <p><span>报告用户发出的警告</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><strong><span>error</span></strong></p>
            </td>
            <td vAlign=top width=498>
            <p><span>报告所有错误情况</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><span>cpp_exception</span></p>
            </td>
            <td vAlign=top width=498>
            <p><span>报告未捕获的</span><span> C++ </span><span>异常</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><span>system_error</span></p>
            </td>
            <td vAlign=top width=498>
            <p><span>报告系统引起的非致命错误</span><span> (</span><span>例如，超时或浮点数异常</span><span>)</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><strong><span>fatal</span></strong></p>
            </td>
            <td vAlign=top width=498>
            <p><span>用户或系统引起的致命错误</span><span> (</span><span>例如，内存访问越界</span><span>)</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=121>
            <p><span>nothing</span></p>
            </td>
            <td vAlign=top width=498>
            <p><span>不报告任何信息</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span>生成测试可执行程序后，可以通过指定</span><span>--log_level</span><span>参数指定日志接别。比如，最后可执行程序为</span><span>testmini</span><span>，执行</span><span>./testmini --log_level=warning</span><span>指定在</span><span>warning</span><span>级别运行，默认执行在</span><span>error</span><span>级别。</span></p>
<p><span>请特别关注级别中黑体部分，</span><span>TestAssert</span><span>中将使用到。</span></p>
<h2><a style="COLOR: #000000" name=_Toc248746757><span><span>3.2 </span></span><span>TestAssert</span></a></h2>
<p><span>Boost.Test</span><span>中测试断言包含如下</span><span>3</span><span>大类：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=624 border=1>
    <tbody>
        <tr>
            <td width=81>
            <p align=center><span>类别</span></p>
            </td>
            <td width=325>
            <p align=center><span>功能</span></p>
            </td>
            <td width=217>
            <p align=center><span>说明</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=81>
            <p><span>WARN</span></p>
            </td>
            <td vAlign=top width=325>
            <p><span>打印</span><span>warning</span><span>日志，不增加失败引用计数，继续执行程序</span></p>
            </td>
            <td vAlign=top width=217>
            <p><span>检验不太重要但是正确的方面</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=81>
            <p><span>CHECK</span></p>
            </td>
            <td vAlign=top width=325>
            <p><span>打印</span><span>error</span><span>日志，增加失败引用计数，继续执行程序</span></p>
            </td>
            <td vAlign=top width=217>
            <p><span>实现</span><span> assertions</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=81>
            <p><span>REQUIRE</span></p>
            </td>
            <td vAlign=top width=325>
            <p><span>增加失败应用计数，中断程序的运行</span></p>
            </td>
            <td vAlign=top width=217>
            <p><span>失败就不应该让程序继续运行则使用</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<p><span>Boost.Test</span><span>中详细测试断言包含如下几种：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=637 border=1>
    <tbody>
        <tr>
            <td width=174>
            <p align=center><span>TestAssert</span><span>类型</span></p>
            </td>
            <td width=173>
            <p align=center><span>说明</span></p>
            </td>
            <td width=290>
            <p align=center><span>举例</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型预言检测</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_WARN(2+2==4);&nbsp;</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型预言检测</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_CHECK(2+2==4);&nbsp;</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型预言检测</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_REQUIRE(2+2==4);&nbsp;</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_MESSAGE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型预言检测，自定义日志</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_WARN_MESSAGE</span><span>（</span><span>2+2==4</span><span>，</span><span>"description&#8230;" );</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_MESSAGE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型预言检测，自定义日志</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_CHECK_MESSAGE</span><span>（</span><span>2+2==4</span><span>，</span><span>"description&#8230;" );</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_MESSAGE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型预言检测，自定义日志</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_ REQUIRE _MESSAGE</span><span>（</span><span>2+2==4</span><span>，</span><span>"description&#8230;" );</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_ERROR</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>同</span><span>BOOST_CHECK_MESSAGE( false, M )</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>if( 2+2 !=4 )</span></p>
            <p><span>BOOST_ERROR( "description&#8230;" );</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_FAIL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>同</span><span>BOOST_REQUIRE_MESSAGE( false, M )</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>if( 2+2 !=4 )</span></p>
            <p><span>BOOST_FAIL( "description&#8230;" );</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_EQUAL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型左右值相等检测检测</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_WARN_EQUAL(2+2,4);</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_EQUAL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型左右值相等检测检测</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_CHECK_EQUAL(2+2,4);</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_EQUAL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型左右值相等检测检测</span></p>
            </td>
            <td vAlign=top width=290>
            <p><span>BOOST_REQUIRE_EQUAL(2+2,4);</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=637 colSpan=3>
            <p><span>该类还有不等，小于，大于，小于等于，大于等于的判别检测，此处只罗列</span><span>WARN</span><span>的，其他不再一一罗列：</span><span>BOOST_WARN_NE/ BOOST_WARN_LT/ BOOST_WARN_LE/ BOOST_WARN_GT/ BOOST_WARN_GE</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_THROW</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型，判别执行函数期，有异常抛出。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left><span>BOOST_WARN_THROW(executeSql(&#8220;select&#8230;&#8221;),oracle::ErrorCodeException);</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_THROW</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型，判别执行函数期，有异常抛出。</span></p>
            </td>
            <td vAlign=top width=290>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_THROW</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型，判别执行函数期，有异常抛出。</span></p>
            </td>
            <td vAlign=top width=290>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_EXCEPTION</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型，执行函数，当预言为真时，捕获异常。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left><span>BOOST_WARN_THROW(executeSql(&#8220;select&#8230;&#8221;),oracle::ErrorCodeException,2+2==4);</span></p>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_EXCEPTION</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型，执行函数，当预言为真时，捕获异常。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_EXCEPTION</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型，执行函数，当预言为真时，捕获异常。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_NO_THROW</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型，判别执行函数期，无异常抛出。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left><span>BOOST_WARN_NO_THROW(executeSql(&#8220;select&#8230;&#8221;));</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_NO_THROW</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型，判别执行函数期，无异常抛出。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_NO_THROW</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型，判别执行函数期，无异常抛出。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_CLOSE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型，判定左右值是否足够逼近。用于浮点数比较。</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left><span>BOOST_WARN_CLOSE</span><span>（</span><span>2.1131,2.1132,0.01</span><span>）</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_CLOSE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型，判定左右值是否足够逼近。用于浮点数比较</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_CLOSE</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型，判定左右值是否足够逼近。用于浮点数比较</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_WARN_SMALL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>WARN</span><span>型，判定值是否足够小（是否接近</span><span>0</span><span>）。用于浮点数比较</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left><span>BOOST_WARN_CLOSE</span><span>（</span><span>0.1,0.01</span><span>）</span></p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_CHECK_SMALL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>CHECK</span><span>型，判定值是否足够小（是否接近</span><span>0</span><span>）。用于浮点数比较</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td vAlign=top width=174>
            <p><span>BOOST_REQUIRE_SMALL</span></p>
            </td>
            <td vAlign=top width=173>
            <p><span>REQUIRE</span><span>型，判定值是否足够小（是否接近</span><span>0</span><span>）。用于浮点数比较</span></p>
            </td>
            <td vAlign=top width=290>
            <p align=left>&nbsp;</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h2><a style="COLOR: #000000" name=_Toc248746758><span><span>3.3 </span></span><span>TestCase</span></a></h2>
<p><span>对于</span><span>TestCase/TestSuite</span><span>等，</span><span>Boost.Test</span><span>既支持手动注册方式，也支持自动注册方式，当前</span><span>Boost</span><span>官方推荐自动注册方式，手动注册为了保持向前兼容保留，以后版本可能被移除。使用宏</span><span>BOOST_AUTO_TEST_CASE</span><span>即可自动注册测试用例。使用如下：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=640 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=640>
            <p><span>#include &lt;boost/test/unit_test.hpp&gt;</span></p>
            <p><span>BOOST_AUTO_TEST_CASE(test_case_name)</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>BOOST_CHECK(true);</span></p>
            <p><span>}</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>&nbsp;</p>
<h2><a style="COLOR: #000000" name=_Toc248746759><span><span>3.4 </span></span><span>TestSuite</span></a></h2>
<p><span>使用宏</span><span>BOOST_AUTO_TEST_SUITE(test_suite_name)</span><span>开始测试套件，使用</span><span>BOOST_AUTO_TEST_SUITE_END()</span><span>结束测试套件。使用举例：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=640 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=640>
            <p><span>#include &lt;boost/test/unit_test.hpp&gt;</span></p>
            <p><span>BOOST_AUTO_TEST_SUITE(test_suite_name)</span></p>
            <p><span>BOOST_AUTO_TEST_CASE(test_case1)</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>BOOST_CHECK(true);</span></p>
            <p><span>}</span></p>
            <p><span>BOOST_AUTO_TEST_CASE(test_case1)</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>BOOST_CHECK(true);</span></p>
            <p><span>}</span></p>
            <p><span>BOOST_AUTO_TEST_SUITE_END()</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h2><a style="COLOR: #000000" name=_Toc248746760><span><span>3.5 </span></span><span>MainTestSuite</span></a></h2>
<p><span>使用宏</span><span>BOOST_TEST_MODULE</span><span>表明主测试套件，一个测试项目中只能存在一个主测试套件。</span><span>使用举例：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=640 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=640>
            <p><span>#define BOOST_TEST_MODULE maintest</span></p>
            <p><span>#include &lt;boost/test/unit_test.hpp&gt;</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<h2><a style="COLOR: #000000" name=_Toc248746761><span><span>3.6 </span></span><span>TestFixture</span></a></h2>
<p><span>测试夹具做测试前的准备工作和测试后的清理工作。而</span><span>C++</span><span>的</span><span>RAII</span><span>机制（构造函数申请资源，析构函数释放资源）恰好能满足该需求。因此</span><span>Boost</span><span>中直接使用普通类做夹具。实现夹具举例：该夹具在测试前将整数</span><span>i</span><span>初始化为</span><span>5</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=640 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=640>
            <p><span>struct MyFixture</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>MyFixture():i(5){}</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>~MyFixture(){}</span></p>
            <p><span>&nbsp;<span>&nbsp;&nbsp;</span>Int I;</span></p>
            <p><span>};</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>夹具可以和</span><span>TestCase</span><span>一起使用，也可以和</span><span>TestSuite</span><span>一起使用，也可以和</span><span>MainTestSuite</span><span>一起使用。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>使用宏</span><span>BOOST_FIXTURE_TEST_CASE(test_case_name, fixure_name)</span><span>代替</span><span>BOOST_AUTO_TEST_CASE(test_case_name)</span><span>即可在</span><span>TestCase</span><span>中使用夹具，举例如下：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=640 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=640>
            <p><span>BOOST_FIXTURE_TEST_CASE(test_case_name</span><span>，</span><span>MyFixture)</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>BOOST_CHECK(i==5);</span></p>
            <p><span>}</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>使用宏</span><span>BOOST_FIXTURE_TEST_SUITE(suite_name, fixure_name)</span><span>代替</span><span>BOOST_AUTO_TEST_SUITE(suite_name)</span><span>即可在</span><span>TestSuite</span><span>中使用夹具，举例如下：</span></p>
<p>
<table cellSpacing=0 cellPadding=0 width=640 border=1>
    <tbody>
        <tr>
            <td vAlign=top width=640>
            <p><span>BOOST_FIXTURE_TEST_SUITE(test_suite, MyFixture );</span></p>
            <p><span>BOOST_AUTO_TEST_CASE (test_case1)</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>BOOST_CHECK(i==5);</span></p>
            <p><span>}</span></p>
            <p><span>BOOST_AUTO_TEST_CASE(test_case2)</span></p>
            <p><span>{</span></p>
            <p><span><span>&nbsp;&nbsp;&nbsp; </span>BOOST_CHECK(++i==6);</span></p>
            <p><span>}</span></p>
            <p><span>BOOST_AUTO_TEST_SUITE_END()</span></p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>使用宏</span><span>BOOST_GLOBAL_FIXTURE(MyFixture);</span><span>将</span><span>MyFixture</span><span>声明为全局夹具，即可和</span><span>MainTestSuite</span><span>一起使用。</span></p>
&nbsp;
<h2><span style="COLOR: #000000">3</span><a style="COLOR: #000000" name=_Toc248746762>.7 Boost.Test</a><span style="COLOR: #000000">使用</span></h2>
<p><span>对已经完成的项目做单元测试，假定该项目具有很好的测试性：</span></p>
<p><span><span>1）<span> </span></span></span><span>对项目中的每个类对象创建一个测试套件，一个测试套件对应一个</span><span>cpp</span><span>文件。对类的每个类方法创建一个测试用例，这些测试用例均包含上前面的测试套件中。每个测试用例可以有多个测试断言，对该方法进行充分测试。</span></p>
<p><span><span>2）<span> </span></span></span><span>在测试主文件中定义宏</span><span>BOOST_TEST_MODULE</span><span>，并包含所有的测试套件文件。</span></p>
<p><span><span>3）<span> </span></span></span><span>Linux</span><span>下，将被测试项目编译成静态库（将</span><span>main</span><span>函数外的所有文件编译打包）供测试项目连接。</span><span>Window</span><span>下为测试项目做静态库工程，设置测试工程依赖该工程。并将头文件路径设置正确，即可编译运行。</span></p>
<p><span>附件为一示例项目以及对应单元测试工程举例，项目目录下</span><span>make</span><span>编译生成静态库以及可执行程序，</span><span>test</span><span>目录下</span><span>make</span><span>生成单元测试可执行程序。(略)<br>&nbsp; </p>
<h1><a name=_Toc248746763><span><span>4&nbsp;</span></span><span>实行单元测试</span></a></h1>
<h2><a style="COLOR: #000000" name=_Toc248746764><span><span>4.1 </span></span><span>现实困难</span></a></h2>
<p><strong><span><span>1、&nbsp;</span></span></strong><strong><span>内部依赖问题</span></strong></p>
<p><span>类之间相互协作共同完成功能，类之间的依赖必不可少。为了测试某个类，必须实例化它依赖的类，而它依赖的类又可能依赖其他类，因此必须实例化其他类。如此一环扣一环，可能把整个项目大部分类都包含在了这次测试中，<strong>最后做的不是单元测试，而是挂着单元测试外壳的集成测试</strong>。</span></p>
<p><strong><span><span>2、&nbsp;</span></span></strong><strong><span>外部依赖问题</span></strong></p>
<p><span>很多项目，尤其是我们的网络应用服务器，运行期间需要依赖外部的其他服务器或者数据库或者本地的文件系统。而对很多外部的依赖很难模拟，或者说模拟成本太高，往往让测试者望而却步。</span></p>
<p><strong><span><span>3、&nbsp;</span></span></strong><strong><span>函数本身问题</span></strong></p>
<p><span>项目中的很多或者可能是大部分函数，是没有明确返回值或者无异常抛出，而只是和其他外设交互。难于使用测试断言判定。</span></p>
<p><span>以上造成很难将某个类从项目中隔离出来，难以设置单元测试点。</span></p>
<h2 style="COLOR: #000000">4<a name=_Toc248746765><span style="COLOR: #000000">.2 解决困难</span></a></h2>
<p><span>上述困难均为依赖造成。</span></p>
<p><strong><span>1</span></strong><strong><span>、内部解依赖</span></strong></p>
<p><span>对被测代码进行解依赖，强化设计，减少耦合，提高代码可测性。解依赖的过程也即为对代码重构过程，减少类间耦合，制造接口层。常用手段有：虚函数、函数指针、传递参数等方式。而对于难于进行解依赖情况，就要考虑提取分化重写方法。</span></p>
<p><strong><span>2</span></strong><strong><span>、写桩代码模拟外部环境</span></strong></p>
<p><span></span><span>单元测试不能直接依赖外部环境，必须写桩代码模拟。而外部环境的可模拟性与内部解依赖紧密相关。对于外部的随机性和各种不确定性，桩代码必须尽可能模拟。</span></p>
<p><strong><span>3</span></strong><strong><span>、开辟访问类私有属性通道</span></strong></p>
<p><span>有些类方法虽然没有明确返回值，但可能修改类的内部状态，可以通过判断类的私有属性来判定类方法的执行情况。可以给类增加</span><span>Get()</span><span>方法或者将私有属性设置为</span><span>protected</span><span>。</span></p>
<p><span>更重要的是在代码开发期，引入</span><span>TDD</span><span>思维，强化设计，提高代码可测性，提高代码的整体质量</span></p>
</span></span>
<img src ="http://www.cppblog.com/CppExplore/aggbug/118850.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2010-06-28 09:15 <a href="http://www.cppblog.com/CppExplore/archive/2010/06/28/118850.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】内存相关分享</title><link>http://www.cppblog.com/CppExplore/archive/2010/03/30/111049.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Tue, 30 Mar 2010 12:35:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2010/03/30/111049.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/111049.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2010/03/30/111049.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/111049.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/111049.html</trackback:ping><description><![CDATA[作者：CppExplore &nbsp;<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a>和<a href="http://blog.csdn.net/cppexplore">http://blog.csdn.net/cppexplore</a>同步发布<br><strong style="FONT-SIZE: 14pt">一 linux内存管理以及内存碎片产生原因</strong><br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img height=217 alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/linux.JPG" width=327 border=0><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最底层使用伙伴算法管理内存页面。系统将所有空闲内存页面分10个组，每个组中的内存块大小依次是1，2，4......512个内存页面，每组中的内存块大小相同，并且以链表结构保存。大小相同，并且内存地址连续的两个内存块称为伙伴。伙伴算法的中心思想就是将成为伙伴的空闲内存合并成一个更大的内存块。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; os中使用get_free_page获取空闲页面，如果找不到合适大小的空闲页面，则从更大的组中找到空闲内存块，分配出去，并将剩余内存分割，插入到合适的组中。当归还内存时，启动伙伴算法合并空闲内存。如果不停的申请内存，并且部分归还，但归还的内存不能成为伙伴，长期运行后，所有内存将被分割成不相邻的小块，当再次申请大块内存时，则可能由于找不到足够大的连续内存块而失败，这种零散的不相邻的小块内存称之为内存碎片。当然这只是理论上的说明，伙伴算法本身就是为了解决内存碎片问题。<br><br><strong style="FONT-SIZE: 14pt">二&nbsp; malloc子系统内存管理（dlmalloc)</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 应用层面的开发并不是直接调用sbrk/mmap之类的函数，而是调用malloc/free等malloc子系统提供的函数，linux上安装的大多为DougLea的dlmalloc或者其变形ptmalloc。下面以dlmalloc为例说明malloc工作的原理。<br><strong>1 dlmalloc下名词解释：</strong><br><strong>&nbsp;&nbsp;&nbsp;boundary tag:</strong> 边界标记，每个空闲内存块均有头部表识和尾部标识，尾部表识的作为是合并空闲内存块时更快。这部分空间属于无法被应用层面使用浪费的内存空间。<br><strong>&nbsp;&nbsp;&nbsp;smallbins:</strong> 小内存箱。dlmalloc将8,16,24......512大小的内存分箱，相临箱子中的内存相差8字节。每个箱子中的内存大小均相同，并且以双向链表连接。<br><strong>&nbsp;&nbsp;&nbsp;treebins:</strong> 树结构箱。大于512字节的内存不再是每8字节1箱，而是一个范围段一箱。比如512~640, 640~896.....每个箱子的范围段依次是128，256，512......。每箱中的结构不再是双向链表，而是树形结构。<br><strong>&nbsp;&nbsp;&nbsp;dv chunk:</strong>&nbsp; 当申请内存而在对应大小的箱中找不到大小合适的内存，则从更大的箱中找一块内存，划分出需要的内存，剩余的内存称之为dv chunk.<br><strong>&nbsp;&nbsp;&nbsp;top chunk:</strong> 当dlmalloc中管理的内存都找不到合适的内存时，则调用sbrk从系统申请内存，可以增长内存方向的chunk称为top chunk.<br><strong>2 内存分配算法</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从合适的箱子中寻找内存块--&gt;从相临的箱子中寻找内存块--&gt;从dv chunk分配内存--&gt;从其他可行的箱子中分配内存--&gt;从top chunk中分配内存--&gt;调用sbrk/mmap申请内存<br><strong>3 内存释放算法</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;临近内存合并--&gt;如属于top chunk，判断top chunk&gt;128k，是则归还系统<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --&gt;不属于chunk，则归相应的箱子<br><br>dlmalloc还有小内存缓存等其他机制。可以看出经过dlmalloc，频繁调用malloc/free并不会产生内存碎片，只要后续还有相同的内存大小的内存被申请，仍旧会使用以前的合适内存，除非大量调用malloc之后少量释放free，并且新的malloc又大于以前free的内存大小，造成dlmalloc不停的从系统申请内存，而free掉的小内存因被使用的内存割断，而使top chunk&lt;128k，不能归还给系统。即便如此，占用的总内存量也小于的确被使用的内存量的2倍（使用的内存和空闲的内存交叉分割，并且空闲的内存总是小于使用的内存大小）。因此可以说，在没有内存泄露的情况，常规频繁调用malloc/free并不会产生内存碎片。<br><br><font style="FONT-SIZE: 14pt" size=5><span style="FONT-SIZE: 14pt"><strong>三&nbsp; 应用层内存池<br></strong></span><span style="FONT-SIZE: 12pt">即便没有内存碎片问题，应用层仍然需要内存池，原因如下：<br>1 使用的内存固定可控&nbsp; 稳定性角度<br>2 减少与内核态交互的可能&nbsp; 性能角度<br>3 减少互斥操作&nbsp; 性能角度，各个线程直接调用malloc，极有可能有线程进入竞态条件，陷入内核态。<br>其中稳定性只能是聊以自慰的说法，os本身都不可信，哪里还来得稳定性的说法。最重要的出发点，是应用层控制内存，提高应用层性能。那么如何创建使用内存池，才能充分提高内存使用的性能呢？我们先从著名的内存池看起。</span><br><br><span style="FONT-SIZE: 14pt"><strong>四&nbsp; 常见内存池<br></strong></span><span style="FONT-SIZE: 12pt">变长内存池：<br>1 apr pool : 针对业务处理，将整个业务场景分段，不同阶段使用不同类型内存池，内存归还池后并不能被再次使用，而是池本身可以被重复使用，特浪费内存。<br>2 obstack: gcc自带变长内存池<br><br>定长内存池：<br>1 SGI STL:&nbsp; 针对小内存做池，字节长度为8,16......128共16个池，每个池中内存大小相同，使用链表连接，小内存采取永不归还malloc子系统策略，大于128直接调用malloc。SGI STL为gcc携带的stl实现。vc以及bc携带的stl，虽然也有allocator对象，但并没有真正的池，而是直接调用malloc。<br><br>2 boost/loki<br>两种内存池采用类似的底层算法，以loki为例子，首次申请一块定长内存，loki会一次性申请255个，之后再次申请从该池中直接获取，从池中申请释放内存算法示例如下：</span><br><img height=145 alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/loki.JPG" width=532 border=0><br><br><span style="FONT-SIZE: 12pt">（1）首次申请内存后，对空闲内存编号，并且前一个内存保存下一块内存的编号，一变量NextBlock保存下次可以申请出的内存块，首次NextBlock=0<br>（2）当申请出3块内存后，NextBlock=3<br>（3）当第二块内存归还时，根据内存基址找到所属的内存chunk，对比chunk基址以及该持中内存块长度，找到该块编号，尾部编号保存NextBlock，NextBlock=1<br>（4）再次归还第三块，第三块尾部保存上次的NextBlock，NextBlock=2<br>（5）再次申请内存，根据NextBlock指定分配出的内存，NextBlock等于该块内存尾部指向的值1.<br>以上模拟stack的压栈出栈行为.<br>loki和boost对内存的处理上有稍许差别，包括内存的组织层次上，这些差别我个人看都是loki相对于boost的缺点。<br>loki/boost代表了当前内存池的最高水准，该池无任何冗余头部（free的内存才保存冗余信息），更节省内存；另外分配释放内存快速，只有固定极少的常数步骤计算。<br>以上算法只是给内存池的后续使用打下坚实基础，并没有给出内存池的使用方式。</span><br><br><span style="FONT-SIZE: 14pt"><strong>五 内存池使用方式分类</strong></span><br></font><span style="FONT-SIZE: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;loki给出了内存池使用的策略，分以下3种：<br>1 全局内存池&nbsp; 所有相同长度的内存申请，使用同一个内存池，不同长度内存申请使用不同内存池。对池中的内存进行申请释放操作时，对池执行加锁操作。<br>2 对象内存池 每个对象一个内存池。内存申请释放执行加锁操作。<br>3 线程内存池 相同长度的内存并且在同一个内存中的内存申请释放使用线程内存池，内存申请释放不执行加锁操作。<br></span><br><span style="FONT-SIZE: 12pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对比第三部分，应用层使用内存池的原因。显然全局内存池并没有解决性能问题，各线程并发申请内存，仍然存在类似直接调用malloc的互斥问题。<br>而对象内存池将这种互斥进一步降低，仅仅跨线程对同一对象申请释放内存才会遇到互斥问题。<br>而线程内存池无疑是最高效的，没有锁开销。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可见最佳的内存池使用方式为，对存在跨线程操作的对象，使用对象内存池，对于只在同一线程内操作的对象使用线程内存池。对象可以通过重载对象的operator new, operator delete等实现。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boost库极其适合进一步封装，供对象内存池和线程内存池（结合thread-specific storage）使用。<br></span><br><strong>六 Linux下内存池终结者</strong><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="FONT-SIZE: 12pt">tcmalloc，可以通过cache等机制智能判断应该使用对象内存池还是线程内存池，编码不需要任何额外策略，直接使用new/delete，只要最后连接上libtcmalloc之类的库即可。可惜仅仅支持linux。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;已有明确的测试数据支持，链接tcmalloc后，原cpu居高不下，突高的服务器程序，大大减少了直接调用malloc的互斥竞态条件出现，cpu趋于平稳。典型的就是linux下链接tcmalloc后重编译的mysql。</span><br><br>
<img src ="http://www.cppblog.com/CppExplore/aggbug/111049.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2010-03-30 20:35 <a href="http://www.cppblog.com/CppExplore/archive/2010/03/30/111049.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】项目管理之 个人小结</title><link>http://www.cppblog.com/CppExplore/archive/2009/09/18/96668.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Fri, 18 Sep 2009 11:58:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2009/09/18/96668.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/96668.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2009/09/18/96668.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/96668.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/96668.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><u><font color="#800080">http://www.cppblog.com/CppExplore/</font></u></a><br /><strong>一 项目管理流程</strong><br /><strong>1 项目定义<br /></strong>在有限的时间、有限的人力、有限的资源内，完成即定的功能，并保证项目的质量。<br />项目具有时效性/资源受限，功能边界明确等特点。<br />项目失败，并不仅仅是指项目的功能没有完成。超时/超支都算做项目失败。<br /><strong>2 项目管理目标<br /></strong>可重复：项目的成功性可复制。一个项目成功，另一个项目也可以成功。成功不是偶然性。<br />可管理：项目本身可管理，成功过程可控。<br /><strong>3 项目生命周期</strong><br />项目具有固有的生命周期规律，项目管理需要遵循该规律，不要过分重视产出（压缩时间），否则影响长期的稳定的产出（同样体现项目管理的可重复、可管理）。<br />项目生命周期分：需求意向 需求阶段 开发阶段 测试阶段 维护阶段。下图给出一个模拟示例：<br /><img style="width: 752px; height: 395px" border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/program.png" width="752" height="395" /> 其中需求结束、开发结束、版本正式发布（测试结束）均为里程碑。<br /><strong>4 参与项目的角色</strong><br />参与项目的主要角色有：项目管理人员/需求人员/研发人员/测试人员/配置人员/实施人员。他们分阶段进入项目，分阶段离开项目。下图为人力投入示例：<img style="width: 763px; height: 188px" border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/effortres.png" width="763" height="188" /> 其中需求来源发生在立项之前，不予考虑，另产品人员需要参加需求文档review，属项目外，不考虑。<br />项目管理人员需要全程跟踪项目，尤其是立项点、需求文档review、需求结束、设计文档review、设计结束、测试期间以后进入维护期后。<br />需求人员除需求阶段，还需要参与设计文档review、测试文档review。<br />开发人员除开发阶段，还需要参与需求文档review，以及测试期间bug修复、维护期保留部分人力。<br />测试人员除开发阶段，还需要参与需求文档review。<br /><strong>二 项目阶段<br />1 立项<br /></strong>立项初期，更多的是资源申请、人力安排计划等。尽量减少以后的沟通成本，比如确定项目编号、阶段编号、功能编号、模块名（如果能够确定）、各模板版本号格式、系统部署的软硬件平台等。<br /><strong>2 需求阶段</strong><br />该阶段是项目最重要的阶段，代表了项目的使命。该阶段的产出需求文档则是项目最重要最核心的一片文档，是设计文档、测试用例以及后期维护的依据。<br /><span style="color: red">需求文档的用语应该是明确的</span>、无歧义的。比如 &#8220;包含...但不限于这些...&#8221;、&#8220;这些功能请研发人员灵活掌握&#8221;&#8220;请参考某某网站/请参照某某项目的样子&#8221;都属于不合格的用语。<br /><span style="color: red">需求文档整体内容应该是封闭的</span>，不依赖于任何未知的内容，引用的外部文档需要嵌在需求文档中，或者给出文档号，可以在团队的文档库中查询到。为更好的理解需求文档的封闭性，举例说明，比如要实现sip栈， 需求文档应该给出sip协议的介绍以及做到什么程度，研发不需要自己去看rfc文档， 只需要参照需求文档去<span style="color: #000000">开发即可</span><span style="color: #000000">。另</span><span style="color: #000000">任何</span><span style="color: #ff0000">业务</span><span style="color: #ff0000">上</span>的知识盲点， 需求人员都要给开发人员解决，开发人员在任何时候(需求文档review中或者设计文档中或者开发中)<span style="color: red">发现业务知识</span>盲点，都可以反馈给需求人员，要求给予支持或解决。<br /><span style="color: red">需求文档需要明确定义系统的功能边界</span><span style="color: red">、系统的网元划分、各个网元的外部特性。</span>这里给出一个大体的提纲：要实现的功能点、网元划分以及最后的部署方式、每个网元的功能点、复杂网元的内部模块图建议（可选）、网元间通讯接口、各网元间的交互时序图、各个网元如何和其他网元交互完成前面的功能点。<br />其中各网元的交互时序图需要能涵盖网元间所有的交互，简单的重复的交互也可用文字描述补充；网元间的通讯接口是明确的，每个命令中的字段名、类型、取值范围都需要明确。<br />其他方面，比如性能要求、其他非功能性要求等，如果外部需求方有明确要求，可写入文档，否则可象征性写一个一定可以满足的值或者省略这部分（性能本身依赖于团队的积累）。<br />在需求文档review阶段，产品人员可以审核考量是否已经满足了预期的功能；开发人员可以审核考量是否已经明确了自己负责的模块特性，是否不再需要和其他模块的开发人员沟通确认某些接口上的问题；测试人员审核考量是否可以依据此写出测试用例，不需要再向开发人员确认。</p>最后需求文档defect入库、文档本身入库。<br /><strong>3 开发阶段</strong><br />开发阶段可以细分为设计文档阶段、编码阶段、测试阶段。其中重要的是前期设计和后期的测试阶段。<br />&nbsp;设计文档中，开发人员要从各个角度向别人展示自己的系统，包括部署图（在网络中的位置）、模块图、数据流向图、<span style="color: #ff0000">静态类图、交互图、状态图</span> 关键数据结构等，最终需要能体现需求文档要求的功能。<br />研发测试阶段请参见<a href="http://www.cppblog.com/CppExplore/archive/2007/11/15/36696.html">测试系列之 c++ server测试全攻略</a>，<span style="color: #000000">其中白盒测试、内存测试、压力测试必做，同时陪测程序需要和源码一并提交在版本管理工具中。完善的log信息和必要的陪测工具是系统质量的保障。</span><br />开发阶段结束后，源码/二进制包上传、代码行统计、各种文档入库、defect入库。<br /><strong>4 测试阶段<br /></strong>测试人员的测试用例、结果必须文档化。专项测试需要包含以下部分：测试目的、测试方法、测试环境、附测试脚本、测试结果。<br />测试人员不仅需要测试系统，在实施和维护期间更要回答现场人员的咨询。<br />测试结束，各种文档入库、defect入库，用户文档产生、版本打标记或者打基线，作为以后开发的基础。<br /><strong>5 实施阶段</strong><br />版本正式发布，基本标志项目结束。实施人员将作为以后现场支持的Level1级，测试人员为Level2级，研发人员为Level3级，属于未实现的功能，转需求人员。<br /><br />说下bug数量，一般c/c++代码每千行16-20个bug左右，研发和测试阶段按一定比例划分。bug过少，从某个角度可以看作测试力度不够，过多可以看作代码质量较差。任何时候，bug数量都不应当作为绩效考核的标准。<br />以上阶段中最重要的是需求阶段，其次是研发阶段的测试。<br /><strong>三 追求更好的项目管理流程<br /></strong>从某种程度上说，项目管理是一个团队的习惯。<br />一个好的项目管理习惯，可以让一个团队的运作如行云流水，又如微风拂面。团队成员各司其责，既是在工作 又何尝不是一种享受。整个项目管理，就象... （就象...最近装修，团购网上的标语：就象）喝茶那样轻松。即便是这个团队从公司脱离，在新的环境里也会保留以前的项目管理制度，从通讯企业里出走的团队很多这种例子。<br />而一个差的项目管理习惯，则是一个团队的噩梦。所谓的管理，可能流于形式，可能成为项目管理者的令箭牌，可能成为研发人员的催命符。<br />习惯的力量强大而可怕。不管是好的团队还是差的团队，遇到不符合自己习惯的改变，都会做出一致的决定：抵制。抵制的理由可能不同 ，有的是 我们现在已经运作的很好了，不需要做出改变，有的则是我们没有那个能力去实施这个流程/我们人员有限/我们控制不住。改变后也不见的运作比现在差，改变后也不见得会浪费更多的人力，反而会有序，更节省人力，更利于控制。<br />养成习惯需要3个前提：知识（知道这么做是好的）、意愿（愿意这样做）、可实施性（有明确的实施方法）。之后加上坚持，一定时间（21天）后就可以形成习惯。<br />看培养好的项目管理习惯就是这么简单，真的就象喝茶那样轻松。<br /><strong>四 团队技术积累</strong> <br />项目管理理论容易给人以错觉，好象只要有了规范的项目管理流程，就可以保证项目的成功可重复/成功过程可控制。但事实往往并不是这么如意。<br />项目管理的顺利进行依赖于团队的基础建设：团队人员组成、基础代码库、基础模块库等。没有完备的团队和一定的基础积累，谈不上项目得可重复与可管理性。<br />成熟的团队中，项目的主角是需求人员、开发人员、测试人员。需求是个迭代的过程，是在已有系统或模块上持续扩充的过程。开发是充实基础库与模块库，在已有基础代码库和基础协议栈之上实现业务的过程。测试是一个测试工具积累的过程。完备的积累是项目成功的可靠保证。<br />总体来说，项目管理和团队建设相辅相成，共同发展，公司在不同的时期，偏重不同，初期重团队建设，成熟期重项目管理。<br /><strong>五 具体问题具体分析 <br /></strong>项目管理流程并非一层不变。针对项目的规模和复杂性，可分大项目、小项目、mini项目。有的项目很小，不需要写需求文档，可能只需要增加一个ChangeRequest，也可能不需要写设计文档。以保证小项目的灵活性和响应及时性。后期的补充正确区分defect和ChangeRequest。需求一定要递交到需求人员，以便其把握整个系统以及后续架构的走向。<br /><br /><br /><img src ="http://www.cppblog.com/CppExplore/aggbug/96668.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2009-09-18 19:58 <a href="http://www.cppblog.com/CppExplore/archive/2009/09/18/96668.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】《java与模式》读书笔记</title><link>http://www.cppblog.com/CppExplore/archive/2009/05/13/82881.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Wed, 13 May 2009 14:18:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2009/05/13/82881.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/82881.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2009/05/13/82881.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/82881.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/82881.html</trackback:ping><description><![CDATA[作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a><br>好久不更新了，拿以前的文章凑凑数，从java那边转一篇过来。<br>
<p>最近发现一本&lt;java与模式&gt;,正好再温故一下当年的专业课内容,下面是这几天记的笔记.(并不是系统的讲解书中的内容)<br><strong style="COLOR: #000000">一&nbsp; 综述:</strong><br>1、不要使用接口定义常量<br>2、自己少用标志接口<br>3、不要继承具体类<br>4、类层次的中间节点应该是接口或者抽象类，叶子是具体类<br>5、子类应当扩展父类的责任，而不是覆写父类的责任<br>6、面向接口编程<br>7、不要滥用继承，组合优先于继承</p>
<p>java中设计不当的类：calendar:作为接口，含有与具体的历法（罗马历法）相关的常量，不能扩展到中国的阴历历法（不符合开闭原则）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; properies类：滥用继承，继承至hashtable，应当使用聚合</p>
<p>8、笛比特法则：只与自己的直接朋友通信，不与陌生人通信（1）狭义笛比特法则：只与朋友通讯，通过自己的朋友传递间接的调用（2）结合依赖倒转原则修改：不必通过朋友传递间接的调用，通过陌生人的抽象接口调用陌生人的行为（依旧不能与具体的陌生人发生通信）<br>9、尽量降低类中成员的访问权限，不要设计退化类（类似c中struct）。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; java中的point2D以及Dinmension2D类有这种设计缺陷（不过这种情况问题不大）<br>10、如果多个具体的产品类没有共同的商业逻辑，就可以把它们抽象到一个接口中，如果有共同的商业逻辑，就把共同的部分抽象到抽象类中，共同的部分尽量向类继承层次的上层移动，以达到复用的目的<br><span style="COLOR: #000000"><strong>二&nbsp;&nbsp; 工厂模式</strong><br></span>1、简单工厂模式：参与角色：工厂/抽象产品类/具体产品类</p>
<p>&nbsp;&nbsp; 缺点：添加新产品的时候，虽然产品相关代码符合开闭原则，但对工厂类本身并不符合，需要修改其中的产生产品方法或者添加新的产生方法（工厂里实现的不同造成的修改不同）来支持新的产品类<br>&nbsp;&nbsp; 退化方式：省略掉工厂角色，抽象产品类担任具体产品类的工厂角色：提供静态的getInstance方法，比如java类库中的DateFormat类，（本人认为这样很不符合开闭原则，父类中出现与具体子类相关的代码，不方便扩展，添加新产品的时候，修改的时候缺点与原简单工厂的工厂角色类似）</p>
<p>2、工厂方法模式：参与角色：抽象工厂类/具体工厂类/抽象产品类/具体产品类<br>&nbsp;&nbsp;&nbsp;&nbsp; 消除了简单工厂的缺点<br>3、抽象工厂模式：简单工厂模式与工厂方法模式的结合</p>
<p>4、单例模式：饿汉和懒汉两种，前者将本身对象作为静态私有属性事先生成，后者推迟到调用的时候，后者需要考虑多线程的时候，前面需要加线程安全关键字（注意），java中还是前者为优。<br>&nbsp;&nbsp; 不要滥用单例，只有系统要求只有一个类的实例的时候才调用<br>&nbsp;&nbsp; 有的单例可能有状态属性，这就为多例模式提供了可能<br>&nbsp;&nbsp; 含有私有属性的类作成单例的时候尤其要注意：一是私有属性的线程安全，确实需要的时候可以加线程安全关键字，比如系统中的log类，二是确认这些属性是不是可以所有线程共享的，类似普通类的static<br><strong>三&nbsp;&nbsp; 各种具体模式（1）</strong><br>1、建造模式：参与角色4个：指导者、抽象建造对象、具体建造对象、产品<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一个复杂的产品有很多的零部件，就可以使用具体的建造对象来一一构造<br>2、原始模式：深拷贝、浅拷贝<br>3、适配器模式：将adaptee类适配成目标接口<br>4、合成模式：参与角色：composite接口、树枝节点类、树叶节点类<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分成透明式和安全式两种，各有优缺点<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)前者将管理子对象的方法放到接口中，这样树型结构中的所有对象都是透明的，都可以统一调用，但是叶节点并没有管理子对象的能力，因此透明但不安全<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)后者将管理子对象的方法下放到树枝节点类中，这样安全但不透明<br>5、装饰模式：继承已有类的接口，提供和已有类相同的方法，并对已有类的功能提供扩展（通过组合已有对象，调用已有对象方法的时候加入新的代码）<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1)透明的装饰模式（纯粹的装饰模式）：装饰类、被装饰类继承于同一接口，而且装饰类只实现接口的方法，不提供额外方法的实现，调用该类的时候使用接口声明调用（实例化当然还是自己的构造函数），即该类的所有方法都是透明的<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2)半透明的装饰模式（退化的装饰模式）：装饰类、被装饰类继承于同一接口，装饰类不仅实现接口的方法，还提供额外方法的实现，这样要调用它独特的方法的时候就必须使用它本身来调用，退化到一半装饰模式、一半适配器模式。<br><strong>四&nbsp;&nbsp; 各种具体模式（2）</strong></p>
<p>1、代理模式：参与角色：代理与真实实体共同的抽象角色、代理角色、真实实体角色<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 远程代理：封装对与远程对象复杂的调用通讯过程，象调用本地对象一样<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 虚拟代理：真实实体加载时间过长的，使用虚拟代理提供友好的显示方式，一边加载实际的对象<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 安全代理：调用真实的对象之前插入权限验证模块<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 智能引用代理：调用真实的对象之后调用统计等相关操作模块</p>
<p>2、享元模式：参与对象：建造工厂、抽象享元、具体享元<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分析对象的内蕴与外蕴状态，即不变的私有属性与变化的私有属性。建造工厂使用备忘录模式存储已经建造的对象，建造对象的时候，以参数的形式传递享元对象的内蕴属性。实际调用中，使用传递外部参数的方法使用外蕴变量。</p>
<p>&nbsp;&nbsp; 复合的享元对象组成的对象，不可以整体使用享元模式，但可以单个的享元对象属性使用该模式<br>&nbsp;&nbsp; 优点：降低内存中的对象&nbsp; 缺点：设计复杂性&nbsp; </p>
<p>3、门面模式：结构模式。为包含有很多对象的子系统提供统一的操作接口类，所有对该子系统的调用都通过这个类，降低子系统之间调用的复杂度，也符合笛比特法则（一个对象的朋友尽量少，只与朋友说话）</p>
<p>4、桥梁模式：参与角色：抽象化角色、抽象化的具体角色、实现化角色、实现化的具体角色两个有继承等级的对象群，一个对象群对另一个对象群有调用关系的时候使用<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目的：使抽象化与实现化解藕<br><strong>五&nbsp;&nbsp; 各种具体模式（3）</strong><br>1、策略：常用于算法族，将算法从依赖的环境中抽象出来形成<br>2、状态：和策略非常接近，使用于有明显状态变化的时候<br>3、命令：命令的发起与执行解藕，命令类可以独立演化，有助于做redo undo操作以及记录所执行的命令<br>4、解释：用于文法的解析<br>5、迭代子：java中有现成的实现，iterator<br>6、观察者：常见，类似与模型视图的关系，java中提供了oberver类和observable接口<br>7、调停者：处理混乱的类交互，抽象出中间类，将类间的交互都通过这个类完成<br>8、模版：将拥有同一父类的多个具体子类的共同操作提取出来形成抽象模版类<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 原则：具体的私有属性应该放到具体类中，抽象类中调用属性通过属性方法而不是直接调用属性<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将私有属性放到具体的类中，才能方便对父类进行多个实现。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将行为看作划分类的标准，以前我都是将数据模型看作划分类的思想，以后应该重新审视行为在类中的重要作用，特别是在的继承等级中。</p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/82881.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2009-05-13 22:18 <a href="http://www.cppblog.com/CppExplore/archive/2009/05/13/82881.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】服务器技术系列综述（三） </title><link>http://www.cppblog.com/CppExplore/archive/2008/12/22/70069.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Mon, 22 Dec 2008 06:27:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/12/22/70069.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/70069.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/12/22/70069.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/70069.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/70069.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a><br>网络请求包经过网络层（<font color=#000080><a href="http://www.cppblog.com/CppExplore/archive/2008/10/23/64783.html"><font color=#000080>技术系列综述（一）</font></a></font>）被解析翻译成程序自定义的消息，之后被投递到业务线程的线程消息队列（<font color=#000080><a href="http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html"><font color=#000080>技术系列综述（二）</font></a></font>）中。业务线程在队列的另一端取出消息，开始处理，这是本章要介绍的部分。业务处理部分：主要有会话类(Session)和会话管理类(SessionManager,常见该类为单例)。先给出类图，后文详细介绍：<br><img height=370 alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/sessionmanager.JPG" width=443 border=0><br><strong>一 SessionManager的职责</strong>：<br><span style="COLOR: red">（1）继承IMsgThread</span>(<a href="http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html"><font color=#000080>技术系列综述（二）</font></a>)，调用该类的start方法，启动业务线程<br><span style="COLOR: red">（2）提供on_.../do_...方法</span>（<a href="http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html"><font color=#000080>技术系列综述（二）</font></a>），供其它线程向业务线程投递消息，以及消息在业务线程的处理入口。<br><span style="COLOR: red">（3）主要的私有属性是session类的容器对象</span>。容器类的选型的依据，首先是查询性能，之后是插入删除的性能。<br><span style="COLOR: red">array：</span>数组下标为session对象的seesionid_(此处sessionid，不要理解为常见协议中的session字段，可以理解为session对象的索引)。可以做到插入删除（参考内存管理chunk分配算法）查询都在o(1)完成，缺点不能动态增大。同样可以参考定长内存池的分配算法，动态申请255个array为一个chunk，所有chunk使用vector管理，各chunk中array编号递增255，同样可以达到增删查o(1)的效率。<br>缺点：（1）sessionid_重复使用，加上消息经过消息队列形成的处理延迟，可能造成下一个session对象处理上一个同样sessionid的session对象遗留下来的消息，实际使用中每个session对象有自己的状态机，这种残留的消息危害并不大。（2）需要自己实现，对比map的o(logn),这点细微的性能提升无任何意义（也就是减少了几次整型之间的对比）。相比不需要自己额外实现的普通数组还算有点实用价值。<br><span style="COLOR: red">vector：</span>如果被插入的session的sessionid是递增的，查询可以做到折半查找logn的性能，但随机删除造成的内存移动是o(n)，无法接受。<br><span style="COLOR: red">map：</span>以红黑树为基础实现。增删查找的性能都可以平稳的保持在o(logn)，sessionid_为整型或者其operater&lt;实现简单的时候是最常用的容器。<br><span style="COLOR: red">hash_map：</span>哈希表，使用大量内存尽量使数据均匀分布，查询性能分hashcode的计算（hash函数）和查找部分，hash函数一般为所有有效信息的移位计算（经典的是字符串的33算法）叠加，查找部分最理想的是0(1),最差是0(n)，取决于hash函数计算结果碰撞的几率。当sessionid_为字符串或者其operater&lt;实现复杂的时候常用。<br><span style="COLOR: red">（4）该类处理消息的方式举例如下</span>：（容器以map&lt;int,session *&gt; mapSessions_为例）</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;do_msg_type_1_(MsgData&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg)<br><img id=Codehighlighter1_34_214_Open_Image onclick="this.style.display='none'; Codehighlighter1_34_214_Open_Text.style.display='none'; Codehighlighter1_34_214_Closed_Image.style.display='inline'; Codehighlighter1_34_214_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_34_214_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_34_214_Closed_Text.style.display='none'; Codehighlighter1_34_214_Open_Image.style.display='inline'; Codehighlighter1_34_214_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_34_214_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_34_214_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;id</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">msg.sessionid;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(mapSessions_.find(id)</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">mapSessions_.end())<br><img id=Codehighlighter1_110_177_Open_Image onclick="this.style.display='none'; Codehighlighter1_110_177_Open_Text.style.display='none'; Codehighlighter1_110_177_Closed_Image.style.display='inline'; Codehighlighter1_110_177_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_110_177_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_110_177_Closed_Text.style.display='none'; Codehighlighter1_110_177_Open_Image.style.display='inline'; Codehighlighter1_110_177_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_110_177_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_110_177_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;session&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pSession</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">mapSessions_[id];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pSession</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">on_msg_1(msg);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_188_212_Open_Image onclick="this.style.display='none'; Codehighlighter1_188_212_Open_Text.style.display='none'; Codehighlighter1_188_212_Closed_Image.style.display='inline'; Codehighlighter1_188_212_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_188_212_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_188_212_Closed_Text.style.display='none'; Codehighlighter1_188_212_Open_Image.style.display='inline'; Codehighlighter1_188_212_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;</span><span id=Codehighlighter1_188_212_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_188_212_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;write_warning_log;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p><br>如上例所示，session管理类对消息的处理方式必须简单固定，方便可持续维护、扩充。<br><strong>二 Session的职责</strong><br>（1）数据结构：每一路连接的业务处理部分，首先有sessionid_标记session本身，其次包含业务处理需要的必须的数据部分，另外最重要的一个数据结构就是状态机了。<br>（2）状态机。状态机标识session对象的状态，接收外部输入的事件，驱动状态机运行，并作出行为响应。详细见<a href="http://www.cppblog.com/CppExplore/archive/2008/01/23/41726.html">《<font color=#000080>技术系列之 状态机（一）</font>》</a>和<a href="http://www.cppblog.com/CppExplore/archive/2008/01/30/42205.html">《<font color=#000080>技术系列之 状态机（二）</font>》</a>，不多说了。<br>（3）方法。主要分两类：on_msg和do_event。举例如下：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;on_msg<img src="http://www.cppblog.com/Images/dot.gif">(MsgData&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">msg)<br><img id=Codehighlighter1_29_103_Open_Image onclick="this.style.display='none'; Codehighlighter1_29_103_Open_Text.style.display='none'; Codehighlighter1_29_103_Closed_Image.style.display='inline'; Codehighlighter1_29_103_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_29_103_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_29_103_Closed_Text.style.display='none'; Codehighlighter1_29_103_Open_Image.style.display='inline'; Codehighlighter1_29_103_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_29_103_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_29_103_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;EventData&nbsp;</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">.detail</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">msg.detail;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">todo</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;fsm.do_event(</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;do_event..(EventData&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #0000ff">event</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_139_230_Open_Image onclick="this.style.display='none'; Codehighlighter1_139_230_Open_Text.style.display='none'; Codehighlighter1_139_230_Closed_Image.style.display='inline'; Codehighlighter1_139_230_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_139_230_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_139_230_Closed_Text.style.display='none'; Codehighlighter1_139_230_Open_Image.style.display='inline'; Codehighlighter1_139_230_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_139_230_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_139_230_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">change&nbsp;session's&nbsp;data&nbsp;or&nbsp;send&nbsp;msg&nbsp;to&nbsp;other&nbsp;thread&nbsp;or&nbsp;response&nbsp;request&nbsp;or&nbsp;others<img src="http://www.cppblog.com/Images/dot.gif">..&nbsp;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span></div>
<p><span style="COLOR: red">注意：<br>1、所有有可能改变session内蕴状态的操作都必须纳入状态机的严格控制，不能存在不通过状态机即可改变session内蕴状态的操作入口。<br>2、如果两个状态对同样的事件做出同样的反应，并且都迁移到相同的状态，那么这两个是同一个状态。<br>3、尽可能减少状态的个数。如果两个状态具有严格的时序关系，处理的事件不同并且有严格的时序关系，那么考虑合并这两个状态，防止状态机膨胀。</span></p>
<p><strong>三 总结：</strong><br>理解业务部分，先区分消息（Msg)和事件(Event)。<br><span style="COLOR: red">1、消息（Msg)：</span>是指线程之间传递的数据结构，即被投递到线程消息队列中的数据结构。SessionManager主要职责是接收消息，通过<span style="COLOR: red">消息映射</span>，找到处理该消息的函数，该函数根据消息中携带的sessionid，找到session对象，调用该session的消息处理函数继续后续的处理。<br><span style="COLOR: red">2、事件(Event)：</span>是指被session对象中的状态机处理的数据结构。该数据结构，在session的消息处理函数中通过消息的内容拼凑，之后交给状态机对象处理，状态机对象根据事件类型，通过<span style="COLOR: red">事件映射</span>，找到处理该事件的函数，继续该事件的处理。<br><span style="COLOR: red">3、代码流程</span>：一般情况下（逻辑控制部分）其它线程不能直接调用session对象，正确的调用方式是发消息SessionManager，SessionManager根据消息找到session对象再进行后续处理。<br><span style="COLOR: red">4、代码要写的足够呆板。<br></span>&nbsp;&nbsp; 写出好的系统关键在于对业务的理解，不在于对代码技巧的玩弄。</p>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/70069.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-12-22 14:27 <a href="http://www.cppblog.com/CppExplore/archive/2008/12/22/70069.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】服务器技术系列综述（二） </title><link>http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Fri, 07 Nov 2008 07:33:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/66216.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/66216.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/66216.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a><br><a title="技术系列综述（一） " href="http://www.cppblog.com/CppExplore/archive/2008/10/23/64783.html">《技术系列综述（一）》</a>介绍了网络层部分。网络层基本都是多路复用函数作为运行的主线程，使用管道或者sockpair与之通讯，这是网络层线程的固有特点，和业务线程的呈现方式完全不同。经过网络层以后，数据开始流向业务线程，现在就顺着数据流向往上看。<br><strong>一 业务线程</strong><br><a title="技术系列之 线程（一） " href="http://www.cppblog.com/CppExplore/archive/2008/01/15/41175.html">《技术系列之 线程（一）》</a>有对线程的一个入门描述，里面的消息队列只是示例，真实可用的可以看<a title="技术系列之 线程（二） " href="http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html">《技术系列之 线程（二）》</a>。<br><span style="COLOR: red">（1）业务线程的划分</span><br>在业务层面，数据结构仍然是服务器程序的核心。整理出业务需要的数据结构，据此划分线程，保证每个数据结构都在它所属的线程中被修改。如果其它线程想修改该结构，则需要向本线程发送消息，由本线程修改。当然这只是理想情况，有时候处于性能的需要或者和网络层的交互，需要跨线程访问其它线程的数据，此时则需要加锁，这也是线程间交互陷入混乱的一个开端，这种情况要限制在一个很小可控的范围内。<br><span style="COLOR: red">（2）带消息队列的线程实现</span><br>OA/CRM/WorkFlow的系统的关键在于业务的整理、面向对象的设计。而网络服务器不同，服务器的业务相对清晰，相关性强，它设计的关键在于数据模型的整理、线程的划分。可以说线程是服务器的骨架。这里引入几乎每个服务器都会有的一个基础模块：带消息队列的线程类。<a title="技术系列之 线程（二） " href="http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html">《技术系列之 线程（二）》</a>实现了一个简单的线程消息队列。在该消息队列基础之上进一步封装，实现带消息队列的线程类。该类的静态类图如下：<br><img height=190 alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/IThread.JPG" width=558 border=0><br>ThreadQueue参见<a title="技术系列之 线程（二） " href="http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html">《技术系列之 线程（二）》</a>。<br>start方法中参数默认为1，大于1则是线程池的实现，里面以线程的方式启动run函数，线程号存入vector，供停止时用。putq方法在其它线程中调用，向该线程发送消息，run方法中循环调用getq获取消息，调用deal_msg处理。实际的业务线程只需要继承该类即可成为带消息队列的线程。<br><span style="COLOR: red">（3）监控线程</span><br>基于上面这个基础模块，可以进一步开发监控线程，监控线程定时向各个线程发送心跳消息，各普通线程收到心跳信息后向监控线程回复，如果某个线程在一定时间内没有回复心跳，则可以采取进一步的修复处理。该方案可以作为系统安全的一个备选方案。<br>以上思想同样适用于嵌入式平台，很多嵌入式平台使用多进程协同处理消息，进程之间使用共享内存或者系统消息队列通讯，思想大同小异，并且同样可以设计监控进程。<br><strong>二 消息映射</strong><br><span style="COLOR: red">（1）消息定义以及处理示例</span><br>有了线程消息队列，也有就有消息传递，接下来就是业务线程获取到消息处理消息。一个业务线程可能要处理多种消息，为区分不同的消息，引入消息类型。如下：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">enum</span><span style="COLOR: #000000">&nbsp;MsgType<br><img id=Codehighlighter1_13_83_Open_Image onclick="this.style.display='none'; Codehighlighter1_13_83_Open_Text.style.display='none'; Codehighlighter1_13_83_Closed_Image.style.display='inline'; Codehighlighter1_13_83_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_13_83_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_13_83_Closed_Text.style.display='none'; Codehighlighter1_13_83_Open_Image.style.display='inline'; Codehighlighter1_13_83_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_13_83_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_13_83_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;MSG_TYPE_1＝</span><span style="COLOR: #000000">65</span><span style="COLOR: #000000">,</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">64一下预留，用于统一的管理控制</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;MSG_TYPE_2,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">..<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;MSG_TYPE_MAX<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;Msg<br><img id=Codehighlighter1_97_129_Open_Image onclick="this.style.display='none'; Codehighlighter1_97_129_Open_Text.style.display='none'; Codehighlighter1_97_129_Closed_Image.style.display='inline'; Codehighlighter1_97_129_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_97_129_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_97_129_Closed_Text.style.display='none'; Codehighlighter1_97_129_Open_Image.style.display='inline'; Codehighlighter1_97_129_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_97_129_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_97_129_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;MsgType&nbsp;type;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;MsgData&nbsp;data;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;</span></div>
<br>业务线程在deal_msg方法中处理消息，很容易想到的处理流程如下：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">switch</span><span style="COLOR: #000000">(msg</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">type)<br><img id=Codehighlighter1_18_199_Open_Image onclick="this.style.display='none'; Codehighlighter1_18_199_Open_Text.style.display='none'; Codehighlighter1_18_199_Closed_Image.style.display='inline'; Codehighlighter1_18_199_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_18_199_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_18_199_Closed_Text.style.display='none'; Codehighlighter1_18_199_Open_Image.style.display='inline'; Codehighlighter1_18_199_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_18_199_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_18_199_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;MSG_TYPE_1:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do_msg_type_1_();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">case</span><span style="COLOR: #000000">&nbsp;MSG_TYPE_2:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do_msg_type_2_();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif">..<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">default</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do_default_msg_();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p><br><span style="COLOR: red">（2）从代码熵引入查表法</span><br>这里引入&#8220;代码熵&#8221;的概念，用于描述代码的混乱程度。每千行代码中，出现一个&#8220;else&#8221;，代码熵加1，出现一个&#8220;case&#8221;，代码熵也加1。如果1k行代码的熵大于7，我们就认为这个代码已经开始变的混乱了。<br>因此当消息类型不多的时候，使用case是个不错的选择，当处理的消息大于7个并且有扩充趋势的时候，我们就要想另外的办法来代替这种switch...case...的写法。<br>消除else和case最直接的想法是查表法，使用数组下标标记消息类型，数组保存消息处理方法指针。这里不使用map，查询需要o(lgn)不如数组来的直接，另外设计期间就已明确知道消息的类型以及对应的处理函数，不需要动态增减，也不需要使用vector，直接简单的方法就是定义一个static的数组表。<br><span style="COLOR: red">（3）消息映射</span><br>直接的数组展现方式不携带语义，展现方式不直观，维护和扩充都让人头大。这里可用借助宏包裹数组，提供可读的展现方式，如下：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">BEGIN_MESSAGE_MAP(SessionManager,SessionMsg)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ON_MESSAGE(MSG_TYPE_1,&nbsp;SessionManager::do_msg_type_1_)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ON_MESSAGE(MSG_TYPE_2,&nbsp;SessionManager::do_msg_type_2_)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/Images/dot.gif"><img src="http://www.cppblog.com/Images/dot.gif"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>END_MESSAGE_MAP()</span></div>
<p>如果你熟悉MFC，一定很熟悉这种消息映射的定义方式。这种消息映射的定义方式，从可维护、可读方面比直接的数组更进了一步。宏BEGIN_MESSAGE_MAP、ON_MESSAGE的实现方式不再详写，如果读者实在想象不出来，可以参见<a title="技术系列之 状态机（一） " href="http://www.cppblog.com/CppExplore/archive/2008/01/23/41726.html">《技术系列之 状态机（一）》</a>中的状态机映射宏的定义方式。使用的时候在deal_msg中直接根据消息类型找到数组中的消息处理函数进行处理，如果你认为这样暴露了消息映射背后的数组结构，可以把这个寻找消息处理函数的工作也封装到基类IMsgThread中。<br><span style="COLOR: #ff0000">（4）成员函数委托</span><br>上面的消息映射宏展开后实际是一个静态数组，而方法do_msg_type_1_/do_msg_type_2_也必须是类的静态成员函数（普通类成员函数指针不能转化为普通函数指针）。通过类的静态成员函数访问类的非静态属性或者方法如下：在消息中携带该类指针handler，处理方法中取到handler指针转换类型，通过指针操作。<br>当代码中充斥大量通过静态成员函数访问对象私有属性的时候，这无疑是一种丑陋的写法（事实并没有这么严重）。<br>这里就该boost::function，boost::bind出场了。如果你喜欢，也可以直接写模版实现。也可以参见csdn文章<a title=成员函数指针与高性能的C++委托 href="http://dev.csdn.net/article/30/30130.shtm"><span style="COLOR: #3366ff">《</span><a href="http://dev.csdn.net/article/30/30130.shtm"><span style="COLOR: #3366ff">成员函数指针与高性能的C++委托》</span></a></a><br><span style="COLOR: #ff0000">（5）题外话<br>1、统一的展现方式。<br></span>不仅变量的命名需要统一规范，方法的调用逻辑同样需要统一，这可以帮助你明确程序中数据的流向以及保证程序持续的扩充、维护。相对于简单的命名规范，方法调用逻辑的统一更为重要。<br>以线程类举例说2点（1)其它线程类不能直接调用其它线程的putq方法向对应线程发送消息。正确的做法是调用对应线程类的方法，由该方法负责向本线程发送消息。<br>(2）发送消息的方法/处理消息的方法职责要明确、命名要统一。<br>发送消息的方法负责把方法参数转化为消息内容，调用putq发送消息，该方法不得操作本类的任何私有属性。<br>处理消息的方法负责对消息做出处理、响应。<br>命名方面，比如发送消息的方法可以以ON_开头，处理消息的方法可以以DO_开头。<br>这些规范不应该只是规范，而应该是发自内心的需要。当然没有什么规范是必须的，你仍然可以使用你喜欢的或者认为可行的方式，如果你的方法在程序1w行、10w行、50w行的时候，仍能清晰表现程序的数据流向，仍有很好的可维护性、可扩充性。<br><span style="COLOR: #ff0000">2、开发领域的烙印。</span><br>不多说了。一句话:重要的是思想，不是平台和语言。</p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/66216.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-11-07 15:33 <a href="http://www.cppblog.com/CppExplore/archive/2008/11/07/66216.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】服务器技术系列综述（一）</title><link>http://www.cppblog.com/CppExplore/archive/2008/10/23/64783.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Thu, 23 Oct 2008 02:55:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/10/23/64783.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/64783.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/10/23/64783.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/64783.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/64783.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><u><font color=#800080>http://www.cppblog.com/CppExplore/</font></u></a><br>本人职业是linux上网络服务器的开发，本文就网络服务器的系统架构设计的细枝末节展开讨论。欢迎任何的点评指导和讨论，尤其是对文中的缺点或者更好的方案。<br><strong>一 系统框架概述</strong><br>网络上的服务器，无论是嵌入式的网络设备，还是pc上服务器，整体结构以及主要思想都大体相同：根据业务模型确定主要数据结构，根据数据结构确定线程模型，在各个业务线程内根据围绕主要数据结构进行的操作确定状态机模型，低层使用网络层收发数据完成和其它网元的通讯。线程交互模型简单描述如下图：<br><img height=205 alt="" src="http://www.cppblog.com/images/cppblog_com/cppexplore/server.JPG" width=428 border=0><br>其中网络层包括收发模块，收数据模块是单独线程，而发数据模块则被业务线程调用在其本身线程中发送数据，网络层收到数据后也可能向多个业务线程发送消息，业务线程可能1个，也可能多个，业务线程之间可能存在消息发送，最终会调用网络层的发送方法完成本server的功能。<br><strong>二 网络层</strong><br>相对而言，网络层的实现相对呆板、模式化，这个层面的要点在系统调用，实现方式要符合操作系统提供的api允许的使用方式，而不能天马行空想当然，因此提高这部分能力的重点在于系统性的学习（《unix网络编程》），不再于经验。<br><strong>网络层有3部分构成</strong>：<span style="COLOR: #000000">连接细节、多路复用函数、协议解析。<br></span><span style="COLOR: #ff0000">（1）连接细节。</span>要实现各个协议的网络层（协议栈），首先要面对的就是承载该协议的传输层协议，udp还是tcp，理论本身就不再多说了。简单说下编程上的差异：udp的网络连接简单、收数据简单，tcp的则网络连接复杂、收数据需要在应用层面确定是否一个收包完毕，tcp部分可以参见<a title="《【原创】技术系列之 网络模型（一）基础篇》" href="http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html">《【原创】技术系列之 网络模型（一）基础篇》</a>。<br><span style="COLOR: #ff0000">（2）多路复用函数。</span>除了处理udp、tcp本身网络连接的系统调用之外，还存在和udp/tcp无关的多路复用函数（select等），它们可以监控tcp的网络事件，也可以监控udp的网络事件，属于网络层的核心驱动部分。可以参见<a title="《【原创】技术系列之 网络模型（三）多路复用模型》" href="http://www.cppblog.com/CppExplore/archive/2008/04/30/48529.html">《【原创】技术系列之 网络模型（三）多路复用模型》<br></a><span style="COLOR: #ff0000">（3）协议解析。</span>这部分相对独立，是网络层中和网络连接、收发消息无关的部分，主要功能则是对该协议各种消息的解包(decode)、打包（encode)。<br>网络层的主要线程是多路复用监控线程（select/poll/epoll_wait等），网络消息触发该线程的运转，如果是收包，则调用read类函数，收包完毕，进行解包操作，之后根据需要向业务线程发送消息（也可以收包完毕后即把数据包裹在消息中发送给业务线程，由业务线程解包，单仍把解包打包操作归在网络层中）。<br><strong>性能方面：</strong>为了描述方便，引入使用场景：转发rtp码流，这个场景需要尽量大的并发行和实时性。<br><span style="COLOR: red">（1）高性能函数。</span>如果系统支持，使用epoll/port/kqueue等高性能多路复用函数。在此，将多路复用监控线程封装在RtpService类中，将rtp连接，封装在RtpConnection类中。使用模型可以参见<font style="COLOR: #000000" color=#ff0000><a title="《【原创】技术系列之 网络模型（二）》" href="http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html"><font style="COLOR: #333399" color=#ff0000>《【原创】技术系列之 网络模型（二）》<br></font></a></font><span style="COLOR: red">（2）多线程支持。</span>启动多个RtpService示例，也既是启动多个多路复用监控线程。将RtpConnection对象均匀的插入到各个RtpService中，同时在RtpConnection中记录它属于的RtpService，便于删除的时候找到它所在的RtpService。<br><span style="COLOR: red">（3）收数据线程直接转发。</span>处于实时性的需要，一定要在收数据的线程转发数据，而不是向其它线程发送消息，让其它线程完成发送。这样做一是避免不必要的内存复制，最重要的是，线程调度引起的时间不确定性不能保证转发的实时性。<br><span style="COLOR: red">（4）读写锁代替普通锁。<span style="COLOR: #000000">分发数据的时候（转发不需要）</span></span>势必要扫描一个容器中的对象，进行分发操作，分发发生在不同的线程中，加锁成为必然。读写锁代替普通锁，使扫描操作不必互斥，也避免（2）中的多线程不能发挥多线程的效果。注意：测试发现，linux2.6内核中的读写锁，只有在静态初时化的时候，才能写优先，使用pthread_rwlock_init进行初始化，不管如何设置它的属性（即便是设置属性为写优先），都不能实现写优先效果，因此需要自己使用pthread_mutex_t和pthread_cond_t实现写优先的读写锁，具体实现的细节就不再多说了（可以参考<a title="《【原创】技术系列之 线程（二）》" href="http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html">《【原创】技术系列之 线程（二）》</a>中线程消息队列中锁的实现），重要的是想法，不是实现。写优先的必要性是因为转发线程活跃频繁，而读线程可以一直进入读锁，造成写线程永久性的处于等待状态。<br><span style="COLOR: red">（5）使用Epoll的ET模式。</span>再此对epoll多说一点，在<a title="《【原创】技术系列之 网络模型（三）多路复用模型》" href="http://www.cppblog.com/CppExplore/archive/2008/04/30/48529.html">《【原创】技术系列之 网络模型（三）多路复用模型》<br></a>中因为我当时的测试场景是普通的http交互，得出&#8220;LT和ET性能相当&#8221;的结论，跟帖中<strong><span style="COLOR: red">网友</span><span style="COLOR: red">bluesky</span></strong>给予更正，非常感谢。在这个rtp转发的场景中，特别适合ET模式，一次触发，必须读尽接收缓冲区的数据，一是保证转发实时性，一是避免剩余数据再次触发（并发高的情况下，多路复用函数的被触发已非常频繁，因此要尽量减少不必要的触发），这个场景下，多一次的读操作微不足道。<br><span style="COLOR: red">（6）减少系统调用次数。</span>系统调用是比内存copy性能更差的操作，这个再后面的文章中会再详细描述。网络层中的系统可以减少的就是read/recv/recvfrom类的操作，极端化低性能的操作就是一次读一个字节，造成系统调用的次数大幅上升，一般的做法，是开辟缓存（比如char buf[4096];），一次读取尽可能多的字节。<br><span style="COLOR: red">（7）二进制包使用结构直接解包，</span><span style="COLOR: red">字符性包延迟解包。</span>这两点的出发点都是尽量减少内存复制。二进制解包举例：首先根据协议规定的包结构，定义结构体。<br>比如（注：<span style="COLOR: red"><strong>网友</strong></span><a id=AjaxHolder_Comments_CommentList_ctl05_NameLink href="http://www.cppblog.com/powervv/" target=_blank><span style="COLOR: red"><strong>powervv</strong></span></a><strong> </strong>跟帖指出，要点在于大小端主机序、网络序和主机序之间的转换、以及字节对齐问题，避免误导读者，举例做出修改）：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;RTPHeader<br><img id=Codehighlighter1_17_384_Open_Image onclick="this.style.display='none'; Codehighlighter1_17_384_Open_Text.style.display='none'; Codehighlighter1_17_384_Closed_Image.style.display='inline'; Codehighlighter1_17_384_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_17_384_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_17_384_Closed_Text.style.display='none'; Codehighlighter1_17_384_Open_Image.style.display='inline'; Codehighlighter1_17_384_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_17_384_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_17_384_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">#if</span><span style="COLOR: #000000">&nbsp;__BYTE_ORDER&nbsp;==&nbsp;__BIG_ENDIAN</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;v:</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;p:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;x:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;cc:</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;m:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;pt:</span><span style="COLOR: #000000">7</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">#else</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;cc:</span><span style="COLOR: #000000">4</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;x:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;p:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;v:</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;pt:</span><span style="COLOR: #000000">7</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;m:</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">#endif</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;seq:</span><span style="COLOR: #000000">16</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;tm:</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;unsigned&nbsp;ssrc:</span><span style="COLOR: #000000">32</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;</span></div>
<p>收数据到buf，解包过程则是：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">Packet&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pack</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(Packet&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)buf</span></div>
<p>完成解包，读取seq的时候，需要ntohs转化，tm同样要ntohl。<br>打包相同：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;buf[1</span><span style="COLOR: #000000">2</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>Packet&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pack</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(Packet&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)buf;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>packe</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">v</span><span style="COLOR: #000000">=2</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><img src="http://www.cppblog.com/Images/dot.gif">.<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>pack</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">seq</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">htons(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);</span></div>
<p>字符性包解包，则一般是预解包扫描buf，将每个字段的偏移和长度记录下来，等需要的时候在进行内存复制操作（常用的则是立即复制出来）。通常将字段使用枚举定义，比如有字段MAX_FIEDS_NUM个，定义开始位置和偏移结构：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">struct</span><span style="COLOR: #000000">&nbsp;FieldLoc<br><img id=Codehighlighter1_16_38_Open_Image onclick="this.style.display='none'; Codehighlighter1_16_38_Open_Text.style.display='none'; Codehighlighter1_16_38_Closed_Image.style.display='inline'; Codehighlighter1_16_38_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_16_38_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_16_38_Closed_Text.style.display='none'; Codehighlighter1_16_38_Open_Image.style.display='inline'; Codehighlighter1_16_38_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_16_38_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_16_38_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;loc;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;len;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;</span></div>
<p>则定义 FieldLoc[MAX_FIEDS_NUM]，准备保存各个字段的偏移和长度。至于扫描字段引起的性能损耗和内存复制引起的性能比较将在后面阐述。<br><span style="COLOR: red">（8）内存池相关、系统调用以及内存复制等的代价这些通用性能部分后面会再有描述。</span></p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/64783.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-10-23 10:55 <a href="http://www.cppblog.com/CppExplore/archive/2008/10/23/64783.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>职业之路</title><link>http://www.cppblog.com/CppExplore/archive/2008/06/18/53814.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Wed, 18 Jun 2008 02:13:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/06/18/53814.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/53814.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/06/18/53814.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/53814.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/53814.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><u><font color=S00080>http://www.cppblog.com/CppExplore/</font></u></a><br>在这个blog上写了几篇技术文章，一是记录下自己对技术的一点浅显的看法，二是在自己的认知范围内揭示系统级别的核心技术，希望能对后来人能有一点帮助。从系统角度而言，技术本身只是实现业务的载体，业务才是系统的灵魂。因此除技术外，也准备写点其它方面的东西，大抵也就是写下面几个系列的文章，技术系列、业务系列、系统系列、测试系列、团队管理系列。以前本blog上起名为系统设计系列的文章，现已全部改名为技术系列了。</p>
<p><span style="COLOR: red">技术系列，</span>在本人的认知范围内，探讨系统级别的核心技术，文章描述的都是技术本身，最终目的是建立公用的模块库，比如含消息队列的线程模块、状态机模块、定时器模块、对象池模块、log模块、网络层模块、管理接口模块等等。</p>
<p>从个人的角度考虑，开发公用模块，可以加深对系统整体的了解，能有更多的时间去了解新的技术、去认识业务的重要性、去考虑系统划分的合理性，不要陷入技术繁琐细节的泥潭，技术仅仅是工具而已，它们背后的原理都很简单。</p>
<p>从团队的角度考虑，开发公有模块，可以增加系统的可维护性、减少对新员工的培训成本、使具有不同业务的系统在技术细节上呈现一致性，形成开发的可持续性，减少对个人技术的依赖，不会因为某个核心人员的离职而造成后续开发的戛然而止。</p>
<p>公有模块开发导致的后果是减少对个人的依赖，因此有的技术人员可能对开发这些模块产生抵触心理。个人认为，技术是没有边际的，单个人是永远也不会掌握所有技术，单纯的技术也不是正确的职业规划，固步自封只能导致自己技术水平的落后。以开放的心态、职业化的心态去做实际的开发、去交流沟通，最终受益的是自己。<br><br><span style="COLOR: red">业务系列</span>的文章写点本人接触过的业务，以公有协议为主线，mgcp、sip、rtsp、rtp、rtcp、加密框架等，协议本身、应用场景等，想想可写的东西也不多，和技术一样，都是很少很简单的东西。</p>
<p><span style="COLOR: red">系统系列</span>，则从业务的角度出发，描述一些通用系统，也就是纯公有协议业务系统。比如说个媒体负载子系统，该子系统可以独立于信令协议，一个信令系统下可以挂载n个媒体子系统，可协同信令系统完成nat穿透、负载均衡、媒体流加解密等功能，使用私有协议和信令系统通讯，可定时比如60秒发一次负载个数信令到信令系统，一是作为心跳，二是作为负载均衡的依据。再比如一些顶层协议无关的proxy系统设计等。<br>从团队、公司的角度来考虑，开发公用系统的重要性不言而喻。开发公用系统也即开发工作由项目驱动转化为产品驱动、根据所做一系列项目的固有特点，找出事物的内在规律，合理划分子系统。<br>开发公用系统，可以降低开发的成本开销，便于公司去开发更多的业务，涉足更多的业务市场，从而形成不断扩大的业务市场，而不是以防守者的姿态，维护自己已有的甚至是逐渐萎缩的业务市场份额。<br><br><span style="COLOR: red">测试系列</span>。测试团队的开发还是集中于业务层面的测试，白盒测试、稳定性测试还是要研发自己来做。写点自己的测试心得。虽然本blog上的技术文章远多于测试，但个人认为测试的重要性大于技术，不重视测试的研发不是一个好研发，也不会成为一个好研发，顶多是一个夸夸其谈的华而不实者。</p>
<p><span style="COLOR: red">团队管理系列，</span>也或许不会写。但从职业发展的角度看，还是应当总结点，在不同的公司感受不同的管理，看看各个公司的相同点不同点，管理的初衷等。团队管理部分，个人看呈现下面几个部分:公司福利/公司制度、项目管理、技术培训、对员工的人文关怀、个人管理等。<br></p>
 <img src ="http://www.cppblog.com/CppExplore/aggbug/53814.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-06-18 10:13 <a href="http://www.cppblog.com/CppExplore/archive/2008/06/18/53814.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 必备外围功能-log</title><link>http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Thu, 05 Jun 2008 01:54:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/52216.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html#Feedback</comments><slash:comments>23</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/52216.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/52216.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 作者：CppExplore 网址：http://www.cppblog.com/CppExplore/log模块是一个小模块，却是每个系统必备的模块。优秀的系统一定会有优秀的log信息，也可以说全面到位的log信息在一定程度上决定了一个系统的健壮性。在linux上，log模块是跟踪程序运行，验证业务逻辑正确的唯一方法。一、功能一个优秀的log系统应该包含以下功能：（1）支持打印到屏幕、文件、soc...&nbsp;&nbsp;<a href='http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html'>阅读全文</a><img src ="http://www.cppblog.com/CppExplore/aggbug/52216.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-06-05 09:54 <a href="http://www.cppblog.com/CppExplore/archive/2008/06/05/52216.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 网络模型（三）多路复用模型</title><link>http://www.cppblog.com/CppExplore/archive/2008/04/30/48529.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Wed, 30 Apr 2008 09:23:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/04/30/48529.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/48529.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/04/30/48529.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/48529.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/48529.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><font color=#000080>http://www.cppblog.com/CppExplore/</font></a><br>多路复用的方式是真正实用的服务器程序，非多路复用的网络程序只能作为学习或着陪测的角色。本文说下个人接触过的多路复用函数：select/poll/epoll/port。kqueue的*nix系统没接触过，估计熟悉了上面四种，kqueue也只是需要熟悉一下而已。<br><strong>一、select模型</strong><br>select原型：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;select(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;n,&nbsp;fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">readfds,&nbsp;fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">writefds,&nbsp;fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">exceptfds,&nbsp;struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">timeout);</span></div>
<p>其中参数n表示监控的所有fd中最大值＋1。<br>和select模型紧密结合的四个宏，含义不解释了：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">FD_CLR(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,&nbsp;fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">set);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>FD_ISSET(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,&nbsp;fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">set);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>FD_SET(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,&nbsp;fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">set);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>FD_ZERO(fd_set&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">set);</span></div>
<p><span style="COLOR: red">理解select模型的关键在于理解fd_set</span>,为说明方便，取fd_set长度为1字节，fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。<br>（1）执行fd_set set; FD_ZERO(&amp;set);则set用位表示是0000,0000。<br>（2）若fd＝5,执行FD_SET(fd,&amp;set);后set变为0001,0000(第5位置为1)<br>（3）若再加入fd＝2，fd=1,则set变为0001,0011<br>（4）执行select(6,&amp;set,0,0,0)阻塞等待<br>（5）若fd=1,fd=2上都发生可读事件，则select返回，此时set变为0000,0011。注意：没有事件发生的fd=5被清空。</p>
<p>基于上面的讨论，可以轻松得出select模型的特点：<br>（1)可监控的文件描述符个数取决与sizeof(fd_set)的值。我这边服务器上sizeof(fd_set)＝512，每bit表示一个文件描述符，则我服务器上支持的最大文件描述符是512*8=4096。据说可调，另有说虽然可调，但调整上限受于编译内核时的变量值。本人对调整fd_set的大小不太感兴趣，参考<a href="http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html">http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html</a>中的模型2（1）可以有效突破select可监控的文件描述符上限。<br>（2）将fd加入select监控集的同时，还要再使用一个数据结构array保存放到select监控集中的fd，一是用于再select返回后，array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空，则每次开始select前都要重新从array取得fd逐一加入（FD_ZERO最先），扫描array的同时取得fd最大值maxfd，用于select的第一个参数。<br>（3）可见select模型必须在select前循环array（加fd，取maxfd），select返回后循环array（FD_ISSET判断是否有时间发生）。</p>
<p>下面给一个伪码说明基本select模型的服务器模型：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">array[slect_len];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>nSock</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>array[nSock</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">listen_fd;(之前listen&nbsp;port已绑定并listen)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>maxfd</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">listen_fd;<br><img id=Codehighlighter1_100_488_Open_Image onclick="this.style.display='none'; Codehighlighter1_100_488_Open_Text.style.display='none'; Codehighlighter1_100_488_Closed_Image.style.display='inline'; Codehighlighter1_100_488_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_100_488_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_100_488_Closed_Text.style.display='none'; Codehighlighter1_100_488_Open_Image.style.display='inline'; Codehighlighter1_100_488_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #0000ff">while</span><span id=Codehighlighter1_100_488_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_100_488_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;FD_ZERO(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">set);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;foreach&nbsp;(fd&nbsp;in&nbsp;array)&nbsp;<br><img id=Codehighlighter1_149_204_Open_Image onclick="this.style.display='none'; Codehighlighter1_149_204_Open_Text.style.display='none'; Codehighlighter1_149_204_Closed_Image.style.display='inline'; Codehighlighter1_149_204_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_149_204_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_149_204_Closed_Text.style.display='none'; Codehighlighter1_149_204_Open_Image.style.display='inline'; Codehighlighter1_149_204_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_149_204_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_149_204_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fd大于maxfd，则maxfd</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">fd<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FD_SET(fd,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">set)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;res=select(maxfd</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">set,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)；<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(FD_ISSET(listen_fd,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">set))<br><img id=Codehighlighter1_272_338_Open_Image onclick="this.style.display='none'; Codehighlighter1_272_338_Open_Text.style.display='none'; Codehighlighter1_272_338_Closed_Image.style.display='inline'; Codehighlighter1_272_338_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_272_338_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_272_338_Closed_Text.style.display='none'; Codehighlighter1_272_338_Open_Image.style.display='inline'; Codehighlighter1_272_338_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_272_338_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_272_338_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newfd</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">accept(listen_fd);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array[nsock</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">newfd;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(--res&lt;=0) continue<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;foreach&nbsp;下标1开始&nbsp;(fd&nbsp;in&nbsp;array)&nbsp;<br><img id=Codehighlighter1_375_486_Open_Image onclick="this.style.display='none'; Codehighlighter1_375_486_Open_Text.style.display='none'; Codehighlighter1_375_486_Closed_Image.style.display='inline'; Codehighlighter1_375_486_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_375_486_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_375_486_Closed_Text.style.display='none'; Codehighlighter1_375_486_Open_Image.style.display='inline'; Codehighlighter1_375_486_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_375_486_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_375_486_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(FD_ISSET(fd,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">set))<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;执行读等相关操作<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果错误或者关闭，则要删除该fd，将array中相应位置和最后一个元素互换就好，nsock减一<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(--res&lt;=0) continue<br><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p><strong>二、poll模型</strong><br>poll原型:</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;poll(struct&nbsp;pollfd&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ufds,&nbsp;unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nfds,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;timeout);<br><img id=Codehighlighter1_77_284_Open_Image onclick="this.style.display='none'; Codehighlighter1_77_284_Open_Text.style.display='none'; Codehighlighter1_77_284_Closed_Image.style.display='inline'; Codehighlighter1_77_284_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_77_284_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_77_284_Closed_Text.style.display='none'; Codehighlighter1_77_284_Open_Image.style.display='inline'; Codehighlighter1_77_284_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>struct&nbsp;pollfd&nbsp;</span><span id=Codehighlighter1_77_284_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_77_284_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_120_140_Open_Image onclick="this.style.display='none'; Codehighlighter1_120_140_Open_Text.style.display='none'; Codehighlighter1_120_140_Closed_Image.style.display='inline'; Codehighlighter1_120_140_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_120_140_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_120_140_Closed_Text.style.display='none'; Codehighlighter1_120_140_Open_Image.style.display='inline'; Codehighlighter1_120_140_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_120_140_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_120_140_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;file&nbsp;descriptor&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_183_204_Open_Image onclick="this.style.display='none'; Codehighlighter1_183_204_Open_Text.style.display='none'; Codehighlighter1_183_204_Closed_Image.style.display='inline'; Codehighlighter1_183_204_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_183_204_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_183_204_Closed_Text.style.display='none'; Codehighlighter1_183_204_Open_Image.style.display='inline'; Codehighlighter1_183_204_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;events;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_183_204_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_183_204_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;requested&nbsp;events&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_247_267_Open_Image onclick="this.style.display='none'; Codehighlighter1_247_267_Open_Text.style.display='none'; Codehighlighter1_247_267_Closed_Image.style.display='inline'; Codehighlighter1_247_267_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_247_267_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_247_267_Closed_Text.style.display='none'; Codehighlighter1_247_267_Open_Image.style.display='inline'; Codehighlighter1_247_267_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">short</span><span style="COLOR: #000000">&nbsp;revents;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_247_267_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_247_267_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;returned&nbsp;events&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;</span></div>
<p>和select相比，两大改进：<br>（1）不再有fd个数的上限限制，可以将参数ufds想象成栈低指针，nfds是栈中元素个数，该栈可以无限制增长<br>（2）引入pollfd结构，将fd信息、需要监控的事件、返回的事件分开保存，则poll返回后不会丢失fd信息和需要监控的事件信息，也就省略了select模型中前面的循环操作，返回后的循环仍然不可避免。另每次poll阻塞操作都会自动把上次的revents清空。<br>poll的服务器模型伪码：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">struct&nbsp;pollfd&nbsp;fds[POLL_LEN];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>unsigned&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nfds</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>fds[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">].fd</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">server_sockfd;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>fds[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">].events</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">POLLIN</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">POLLPRI;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>nfds</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img id=Codehighlighter1_118_249_Open_Image onclick="this.style.display='none'; Codehighlighter1_118_249_Open_Text.style.display='none'; Codehighlighter1_118_249_Closed_Image.style.display='inline'; Codehighlighter1_118_249_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_118_249_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_118_249_Closed_Text.style.display='none'; Codehighlighter1_118_249_Open_Image.style.display='inline'; Codehighlighter1_118_249_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #0000ff">while</span><span id=Codehighlighter1_118_249_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_118_249_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;res=poll(fds,nfds,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br><img id=Codehighlighter1_178_194_Open_Image onclick="this.style.display='none'; Codehighlighter1_178_194_Open_Text.style.display='none'; Codehighlighter1_178_194_Closed_Image.style.display='inline'; Codehighlighter1_178_194_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_178_194_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_178_194_Closed_Text.style.display='none'; Codehighlighter1_178_194_Open_Image.style.display='inline'; Codehighlighter1_178_194_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(fds[</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">].revents</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">(POLLIN</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">POLLPRI))</span><span id=Codehighlighter1_178_194_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_178_194_Open_Text><span style="COLOR: #000000">{执行accept并加入fds中,if(--res&lt;=0)continue}</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_243_247_Open_Image onclick="this.style.display='none'; Codehighlighter1_243_247_Open_Text.style.display='none'; Codehighlighter1_243_247_Closed_Image.style.display='inline'; Codehighlighter1_243_247_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_243_247_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_243_247_Closed_Text.style.display='none'; Codehighlighter1_243_247_Open_Image.style.display='inline'; Codehighlighter1_243_247_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;循环之后的fds，</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(fds[i].revents</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">(POLLIN</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">POLLERR&nbsp;))</span><span id=Codehighlighter1_243_247_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_243_247_Open_Text><span style="COLOR: #000000">{操作略if(--res&lt;=0)continue}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
注意select和poll中res的检测，可有效减少循环的次数，这也是大量死连接存在时，select和poll性能下降厉害的原因。<br>
<p><strong>三、epoll模型</strong></p>
<p>epoll阻塞操作的原型：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;epoll_wait(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;epfd,&nbsp;struct&nbsp;epoll_event&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;events,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;maxevents,&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;timeout)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>epoll引入了新的结构epoll_event。<br><img id=Codehighlighter1_132_265_Open_Image onclick="this.style.display='none'; Codehighlighter1_132_265_Open_Text.style.display='none'; Codehighlighter1_132_265_Closed_Image.style.display='inline'; Codehighlighter1_132_265_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_132_265_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_132_265_Closed_Text.style.display='none'; Codehighlighter1_132_265_Open_Image.style.display='inline'; Codehighlighter1_132_265_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>typedef&nbsp;union&nbsp;epoll_data&nbsp;</span><span id=Codehighlighter1_132_265_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_132_265_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">ptr;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__uint32_t&nbsp;u32;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__uint64_t&nbsp;u64;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;epoll_data_t;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_313_445_Open_Image onclick="this.style.display='none'; Codehighlighter1_313_445_Open_Text.style.display='none'; Codehighlighter1_313_445_Closed_Image.style.display='inline'; Codehighlighter1_313_445_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_313_445_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_313_445_Closed_Text.style.display='none'; Codehighlighter1_313_445_Open_Image.style.display='inline'; Codehighlighter1_313_445_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;epoll_event&nbsp;</span><span id=Codehighlighter1_313_445_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_313_445_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_352_369_Open_Image onclick="this.style.display='none'; Codehighlighter1_352_369_Open_Text.style.display='none'; Codehighlighter1_352_369_Closed_Image.style.display='inline'; Codehighlighter1_352_369_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_352_369_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_352_369_Closed_Text.style.display='none'; Codehighlighter1_352_369_Open_Image.style.display='inline'; Codehighlighter1_352_369_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;__uint32_t&nbsp;events;&nbsp;&nbsp;</span><span id=Codehighlighter1_352_369_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_352_369_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;Epoll&nbsp;events&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_408_431_Open_Image onclick="this.style.display='none'; Codehighlighter1_408_431_Open_Text.style.display='none'; Codehighlighter1_408_431_Closed_Image.style.display='inline'; Codehighlighter1_408_431_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_408_431_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_408_431_Closed_Text.style.display='none'; Codehighlighter1_408_431_Open_Image.style.display='inline'; Codehighlighter1_408_431_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;epoll_data_t&nbsp;data;&nbsp;&nbsp;</span><span id=Codehighlighter1_408_431_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_408_431_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">&nbsp;User&nbsp;data&nbsp;variable&nbsp;</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">;</span></div>
<p>与以上模型的优点：<br>（1）它保留了poll的两个相对与select的优点<br>（2）epoll_wait的参数events作为出参，直接返回了有事件发生的fd，epoll_wait的返回值既是发生事件的个数，省略了poll中返回之后的循环操作。<br>（3）不再象select、poll一样将标识符局限于fd，epoll中可以将标识符扩大为指针，大大增加了epoll模型下的灵活性。<br>epoll的服务器模型伪码：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">epollfd</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">epoll_create(EPOLL_LEN);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>epoll_ctl(epollfd,EPOLL_CTL_ADD,server_sockfd,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ev)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>struct&nbsp;epoll_event&nbsp;events[EPOLL_MAX_EVENT];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000"><br><img id=Codehighlighter1_134_226_Open_Image onclick="this.style.display='none'; Codehighlighter1_134_226_Open_Text.style.display='none'; Codehighlighter1_134_226_Closed_Image.style.display='inline'; Codehighlighter1_134_226_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_134_226_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_134_226_Closed_Text.style.display='none'; Codehighlighter1_134_226_Open_Image.style.display='inline'; Codehighlighter1_134_226_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_134_226_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_134_226_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>nfds</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">epoll_wait(epollfd,events,EPOLL_MAX_EVENT,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>循环nfds，是server_sockfd则accept，否则执行响应操作<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p>epoll使用中的问题：<br>（1）epoll_ctl的EPOLL_CTL_DEL操作中，最后一个参数是无意义的，但是在小版本号过低的2.6内核下要求最后一个参数一定非NULL，否则返回失败，并且返回的errno在man epoll_ctl中不存在，因此安全期间，保证epoll_ctl的最后一个参数总非NULLL。<br>（2）如果一个fd（比如管道）的事件导致了另一个fd2的删除，则必须扫描返回结果集中是否有fd2，有则在结果集中删除，避免冲突。<br>（3）有文章说epoll在G网环境下性能会低于poll/select，看有些测试，给出的拐点在2w/s并发之后，我本人的工作范围不可能达到这么高的并发，个人在测试性能的时候最大也是取的1w/s的并发，一个是因为系统单进程允许打开的文件描述符最大值，4w的数字太高了，另一个就是我这边服务器的性能达不到那么高的性能，极限1.7w/s的响应，那测试的数据竟然在2w并发的时候还有2w的响应，不知道是什么硬件配置。或许等有了G网的环境，会关注epoll高并发下的性能下降</p>
<p>。<br>（4）epoll的LT和ET性能的差异，我测试的数据表明两者性能相当，&#8220;使用epoll就是为了高性能，就是要使用ET模式&#8221;这个说法是站不住脚的。个人倾向于使用LT模式，编程简单、安全。</p>
<p><strong>四、port模型</strong><br>port则和epoll非常接近，不需要前后的两次扫描，直接返回有事件的结果，可以象epoll一样绑定指针，不同点是<br>（1）epoll可以返回多个事件，而port一次只返回一个（port_getn可以返回多个，但是在不到指定的n值时，等待直到达到n个）<br>（2）port返回的结果会自动port_dissociate，如果要再次监控，需要重新port_associate<br>这个就不多说了。</p>
<p><span style="COLOR: red">可以看出select--&gt;poll--&gt;epoll/port的演化路线：</span><br>（1）从readset、writeset等分离到 将读写事件集中到统一的结构<br>（2）从阻塞操作前后的两次循环 到 之后的一次循环&nbsp; 到精确返回有事件发生的fd<br>（3）从只能绑定fd信息，到可以绑定指针结构信息</p>
<p><strong>五、抽象接口</strong><br>综合以上多路复用函数的特点，可以进行统一的封装，这里给出我封装的接口，也算是给一个思路：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;init()</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;wait()</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;next_result()</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;delete_from_results(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;data)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;get_data(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;event)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;get_event(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;event)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;add_data(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,XPollData&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;data)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;delete_data(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,XPollData&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">data)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;change_data(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,XPollData&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">data)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;virtual&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;reset_data(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;fd,XPollData&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">data)</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;</span></div>
<p>使用的时候就是先init，再wait，再循环执行next_result直到空，每个result，使用get_data和get_event挨个处理，如果某个fd引起另一个fd关闭，调delete_from_results（除epoll，其它都直接return），处理完reset_data（select和port用，poll/epoll直接return）。<br></p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/48529.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-04-30 17:23 <a href="http://www.cppblog.com/CppExplore/archive/2008/04/30/48529.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 定时器（二）</title><link>http://www.cppblog.com/CppExplore/archive/2008/04/03/46211.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Thu, 03 Apr 2008 13:49:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/04/03/46211.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/46211.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/04/03/46211.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/46211.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/46211.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/"><font color=#000080>http://www.cppblog.com/CppExplore/</font></a><br><strong>一、上篇文章描述。</strong>文章《定时器（一）》<a href="http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html">http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html</a>实现了一个定时器模块，这个实现每次延时时间到都要扫描所有的定时器对象，效率低下。开始设想的时候，LIST中的定时器对象保存间隔时间段的毫秒值，导致每次延时时间到都要做&#8220;时间减少操作&#8221;直到减少到零，并且得出不需排序的结论。<br><strong>二、改进。</strong>如果其中保存超时的精确时间点，而不是保存时间段，则可以在LIST中根据超时时间点对定时器对象排序，延时时间到，则从链表头扫描定时器对象，取其超时时间点与当前时间点对比，如果小于等于当前时间点，则进行超时处理，否则终止继续扫描，避免不必要的扫描操作。同时插入对象的时候插入到合适的位置，以保持链表的顺序化。<br><strong>三、主要数据结构。</strong>此次容器结构选择内核数据结构中的TAILQ，因为LIST没有插入尾部操作（当要插入的定时器对象超时时间点大于所有队列中的对象的时候）。<br><strong>四、新的时间类型操作</strong>。另一方面很多地方涉及到对struct timeval结构的操作，这里介绍几个对该结构进行操作的宏，都已经在系统头文件中定义，可以使用函数原型的方式理解就是如下：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">timeradd(struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p1,struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p2,struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>timersub(struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p1,struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p2,struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>timercmp(struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p1,struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p2,operator&nbsp;op);</span></div>
<p>对struct timespec同样有timespecadd/timespecsub/timespeccmp，另外还有两者的转换宏，使用函数原型的方式理解就是：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">TIMEVAL_TO_TIMESPEC(struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p1,struct&nbsp;timespec&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>TIMESPEC_TO_TIMEVAL(struct&nbsp;timespec&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">p1,struct&nbsp;timeval&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">result);</span></div>
<p>如果系统的头文件中找不到，也可以自己实现下，明白这两个结构的细节结构，实现也很简单，这里拿timeradd举例，其它不说了。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#define&nbsp;&nbsp;&nbsp;&nbsp;timeradd(tvp,&nbsp;uvp,&nbsp;vvp)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img id=Codehighlighter1_44_279_Open_Image onclick="this.style.display='none'; Codehighlighter1_44_279_Open_Text.style.display='none'; Codehighlighter1_44_279_Closed_Image.style.display='inline'; Codehighlighter1_44_279_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_44_279_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_44_279_Closed_Text.style.display='none'; Codehighlighter1_44_279_Open_Image.style.display='inline'; Codehighlighter1_44_279_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">do</span><span style="COLOR: #000000">&nbsp;</span><span id=Codehighlighter1_44_279_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_44_279_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_sec&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(tvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_sec&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;(uvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_sec;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_usec&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;(tvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_usec&nbsp;</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">&nbsp;(uvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_usec;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img id=Codehighlighter1_197_267_Open_Image onclick="this.style.display='none'; Codehighlighter1_197_267_Open_Text.style.display='none'; Codehighlighter1_197_267_Closed_Image.style.display='inline'; Codehighlighter1_197_267_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_197_267_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_197_267_Closed_Text.style.display='none'; Codehighlighter1_197_267_Open_Image.style.display='inline'; Codehighlighter1_197_267_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;((vvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_usec&nbsp;</span><span style="COLOR: #000000">&gt;=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1000000</span><span style="COLOR: #000000">)&nbsp;</span><span id=Codehighlighter1_197_267_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_197_267_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_sec</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(vvp)</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">tv_usec&nbsp;</span><span style="COLOR: #000000">-=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1000000</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)</span></div>
<strong>五、实现。</strong>和上篇文章相比，改动比较的在add_timer_和process方法。当前add_timer_操作需要顺序扫描插入到合适的位置以保持链表的顺序。当前process的主要代码如下：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_44_907_Open_Image onclick="this.style.display='none'; Codehighlighter1_44_907_Open_Text.style.display='none'; Codehighlighter1_44_907_Closed_Image.style.display='inline'; Codehighlighter1_44_907_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_44_907_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_44_907_Closed_Text.style.display='none'; Codehighlighter1_44_907_Open_Image.style.display='inline'; Codehighlighter1_44_907_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_state</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">TIMER_MANAGER_START)</span><span id=Codehighlighter1_44_907_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_44_907_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;tm.tv_sec</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_interval.tv_sec;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;tm.tv_usec</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_interval.tv_usec;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(select(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">tm)</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">errno</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">EINTR);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;gettimeofday(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">now,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img id=Codehighlighter1_194_205_Open_Image onclick="this.style.display='none'; Codehighlighter1_194_205_Open_Text.style.display='none'; Codehighlighter1_194_205_Closed_Image.style.display='inline'; Codehighlighter1_194_205_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_194_205_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_194_205_Closed_Text.style.display='none'; Codehighlighter1_194_205_Open_Image.style.display='inline'; Codehighlighter1_194_205_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span id=Codehighlighter1_194_205_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_194_205_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">加上误差补偿时间</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;timeradd(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">now,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">manager－</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">m_repair,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">stand);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_lock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_mutex);<br><img id=Codehighlighter1_337_861_Open_Image onclick="this.style.display='none'; Codehighlighter1_337_861_Open_Text.style.display='none'; Codehighlighter1_337_861_Closed_Image.style.display='inline'; Codehighlighter1_337_861_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_337_861_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_337_861_Closed_Text.style.display='none'; Codehighlighter1_337_861_Open_Image.style.display='inline'; Codehighlighter1_337_861_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;TAILQ_FOREACH(item,&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">(manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">list_),&nbsp;entry_)</span><span id=Codehighlighter1_337_861_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_337_861_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_339_377_Open_Image onclick="this.style.display='none'; Codehighlighter1_339_377_Open_Text.style.display='none'; Codehighlighter1_339_377_Closed_Image.style.display='inline'; Codehighlighter1_339_377_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_339_377_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_339_377_Closed_Text.style.display='none'; Codehighlighter1_339_377_Open_Image.style.display='inline'; Codehighlighter1_339_377_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span id=Codehighlighter1_339_377_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_339_377_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">取修正后的时间逐个和定时器中的超时时间点相比，遇到不超时对象则退出扫描</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_420_840_Open_Image onclick="this.style.display='none'; Codehighlighter1_420_840_Open_Text.style.display='none'; Codehighlighter1_420_840_Closed_Image.style.display='inline'; Codehighlighter1_420_840_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_420_840_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_420_840_Closed_Text.style.display='none'; Codehighlighter1_420_840_Open_Image.style.display='inline'; Codehighlighter1_420_840_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(timercmp(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_endtime,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">stand,</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">))</span><span id=Codehighlighter1_420_840_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_420_840_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_func)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_func(item,item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_data);<br><img id=Codehighlighter1_518_611_Open_Image onclick="this.style.display='none'; Codehighlighter1_518_611_Open_Text.style.display='none'; Codehighlighter1_518_611_Closed_Image.style.display='inline'; Codehighlighter1_518_611_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_518_611_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_518_611_Closed_Text.style.display='none'; Codehighlighter1_518_611_Open_Image.style.display='inline'; Codehighlighter1_518_611_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_type</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">CTimer::TIMER_ONCE)</span><span id=Codehighlighter1_518_611_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_518_611_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">remove_timer_(item);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_state</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CTimer::TIMER_TIMEOUT;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img id=Codehighlighter1_659_836_Open_Image onclick="this.style.display='none'; Codehighlighter1_659_836_Open_Text.style.display='none'; Codehighlighter1_659_836_Closed_Image.style.display='inline'; Codehighlighter1_659_836_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_659_836_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_659_836_Closed_Text.style.display='none'; Codehighlighter1_659_836_Open_Image.style.display='inline'; Codehighlighter1_659_836_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">else</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_type</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">CTimer::TIMER_CIRCLE)</span><span id=Codehighlighter1_659_836_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_659_836_Open_Text><span style="COLOR: #000000">{<br><img id=Codehighlighter1_661_716_Open_Image onclick="this.style.display='none'; Codehighlighter1_661_716_Open_Text.style.display='none'; Codehighlighter1_661_716_Closed_Image.style.display='inline'; Codehighlighter1_661_716_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_661_716_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_661_716_Closed_Text.style.display='none'; Codehighlighter1_661_716_Open_Image.style.display='inline'; Codehighlighter1_661_716_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span id=Codehighlighter1_661_716_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">/**/</span><span id=Codehighlighter1_661_716_Open_Text><span style="COLOR: #008000">/*</span><span style="COLOR: #008000">循环性的要保证链表的顺序性，如要重新插入，保存entry_的原因，是执行新的插入后不要影响当前进行的循环</span><span style="COLOR: #008000">*/</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmpTimer.entry_</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">item</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">entry_;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">remove_timer_(item);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">add_timer_(item);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; item</span><span style="COLOR: #000000">=&amp;</span><span style="COLOR: #000000">tmpTimer;}<br></span></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #0000ff">else </span><span style="COLOR: #0000ff">break</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_unlock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">manager</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_mutex);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>
<br><strong>六、源码</strong><br>写了个简单的makefile，执行make就可以生成测试程序:test，执行./test可以看运行效果。make由make so和make test组成，make so在lib目录下生成libtimer.a。make clean清空。<br>源代码下载<a href="http://www.cppblog.com/Files/CppExplore/timer.tar.gz">这里</a>： <a style="COLOR: #0000ff" href="http://www.cppblog.com/Files/CppExplore/timer.tar.gz">http://www.cppblog.com/<span style="COLOR: #0000ff">Files/CppExplore/timer.tar.gz</a></span>&nbsp; [make so有问题，貌似so是关键字，下载后把so改下，随意什么单词。]<br><strong>七、后记</strong><br>与上一版本相比，该文中的定时器实现要求在定时器模块运行期间不能修改系统实际，上一版本实现则无此限制。<br>定时器模块的锁初始化为fastmutex方式，因此在回调函数里注意不能再调用CTimer的start stop reset等方法，以免死锁，如果有调用的需求，可以把锁修改为循环锁recmutex方式。<br>&nbsp;<br><strong>2008/4/8补记：</strong>本文是timer的v2实现，定时器timer在业务线程中执行start的时候，要执行扫描排序操作，导致返回时间延长。后续修改：<br>(1)定时器timer的start操作不再执行扫描操作，而是简单插入队列头同时置一变量表示尚未排序。定时器线程延迟时间到，首先扫描未排序对象，执行排序（一次性timer从尾部扫描对比，循环性从头部扫描对比），再扫描判断是否超时。<br>(2)func移动到锁外执行。<br>针对windows客户端栈使用定时器不多，并且定时间隔不能受系统时间影响（客户端的系统时间可能被修改），仍然使用v1的实现。
<img src ="http://www.cppblog.com/CppExplore/aggbug/46211.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-04-03 21:49 <a href="http://www.cppblog.com/CppExplore/archive/2008/04/03/46211.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 定时器（一）</title><link>http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Wed, 02 Apr 2008 15:19:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/46111.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html#Feedback</comments><slash:comments>31</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/46111.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/46111.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 作者：CppExplore 网址：http://www.cppblog.com/CppExplore/一、&nbsp;基础知识1、时间类型。Linux下常用的时间类型有4个：time_t，struct timeval，struct timespec，struct tm。（1）time_t是一个长整型，一般用来表示用1970年以来的秒数。（2）Struct timeval有两个成员，一个是秒，一个是...&nbsp;&nbsp;<a href='http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html'>阅读全文</a><img src ="http://www.cppblog.com/CppExplore/aggbug/46111.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-04-02 23:19 <a href="http://www.cppblog.com/CppExplore/archive/2008/04/02/46111.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 网络模型（二）</title><link>http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Fri, 21 Mar 2008 09:16:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/45061.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/45061.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/45061.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 网址：<a href="http://www.cppblog.com/CppExplore/">http://www.cppblog.com/CppExplore/</a><br>本章主要列举服务器程序的各种网络模型，示例程序以及性能对比后面再写。<br><strong>一、分类依据。</strong>服务器的网络模型分类主要依据以下几点<br>（1）是否阻塞方式处理请求，是否多路复用，使用哪种多路复用函数<br>（2）是否多线程，多线程间如何组织<br>（3）是否多进程，多进程的切入点一般都是accept函数前<br><strong>二、分类。</strong>首先根据是否多路复用分为三大类：<br>（1）阻塞式模型<br>（2）多路复用模型<br>（3）实时信号模型<br><strong>三、详细分类。</strong><br><strong>1、阻塞式模型根据是否多线程分四类：<br></strong><span style="COLOR: red">（1）单线程处理。</span>实现可以参见<a href="http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html">http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html</a>后面的示例代码。<br><span style="COLOR: red">（2）一个请求一个线程。</span><br>主线程阻塞在accept处，新连接到来，实时生成线程处理新连接。受限于进程的线程数，以及实时创建线程的开销，过多线程后上下文切换的开销，该模型也就是有学习上价值。<br><span style="COLOR: red">（3）预派生一定数量线程，并且所有线程阻塞在accept处。<br></span>该模型与下面的（4）类似与线程的领导者/追随者模型。<br>传统的看法认为多进程（linux上线程仍然是进程方式）同时阻塞在accept处，当新连接到来时会有&#8220;惊群&#8221;现象发生，即所有都被激活，之后有一个获取连接描述符返回，其它再次转为睡眠。linux从2.2.9版本开始就不再存在这个问题，只会有一个被激活，其它平台依旧可能有这个问题，甚至是不支持所有进程直接在accept阻塞。<br><span style="COLOR: red">（4）预派生一定数量线程，并且所有线程阻塞在accept前的线程锁处。<br></span>一次只有一个线程能阻塞在accept处。避免不支持所有线程直接阻塞在accept，并且避免惊群问题。特别是当前linux2.6的线程库下，模型（3）没有存在的价值了。另有文件锁方式，不具有通用性，并且效率也不高，不再单独列举。<br><span style="COLOR: red">（5）主线程处理accept，预派生多个线程（线程池）处理连接。<br></span>类似与线程的半同步/半异步模型。<br>主线程的accept返回后，将clientfd放入预派生线程的线程消息队列，线程池读取线程消息队列处理clientfd。主线程只处理accept，可以快速返回继续调用accept，可以避免连接爆发情况的拒绝连接问题，另加大线程消息队列的长度，可以有效减少线程消息队列处的系统调用次数。<br><span style="COLOR: red">（6）预派生多线程阻塞在accept处，每个线程又有预派生线程专门处理连接。<br><span style="COLOR: #000000">（</span></span>3）和（4）/（5）的复合体。<br>经测试，（5）中的accept线程处理能力非常强，远远大于业务线程，并发10000的连接数也毫无影响，因此该模型没有实际意义。<br><span style="COLOR: #ff0000">总结</span>：就前五模型而言，性能最好的是模型（5）。模型（3）/(4)可以一定程度上改善模型（1）的处理性能，处理爆发繁忙的连接，仍然不理想。。阻塞式模型因为读的阻塞性，容易受到攻击，一个死连接（建立连接但是不发送数据的连接）就可以导致业务线程死掉。因此内部服务器的交互可以采用这类模型，对外的服务不适合。优先（5），然后是（4），然后是（1），其它不考虑。<br><strong>2、多路复用模型根据多路复用点、是否多线程分类：</strong><br>以下各个模型依据选用select/poll/epoll又都细分为3类。下面个别术语采用select中的，仅为说明。<br><span style="COLOR: #ff0000">（1）accept函数在多路复用函数之前，主线程在accept处阻塞，多个从线程在多路复用函数处阻塞。</span>主线程和从线程通过管道通讯，主线程通过管道依次将连接的clientfd写入对应从线程管道，从线程把管道的读端pipefd作为fd_set的第一个描述符，如pipefd可读，则读数据，根据预定义格式分解出clientfd放入fd_set，如果clientfd可读，则read之后处理业务。<br>此方法可以避免select的fd_set上限限制，具体机器上select可以支持多少个描述符，可以通过打印sizeof(fd_set)查看，我机器上是512字节，则支持512&#215;8＝4096个。为了支持多余4096的连接数，此模型下就可以创建多个从线程分别多路复用，主线程accept后平均放入（顺序循环）各个线程的管道中。创建5个从线程以其对应管道，就可以支持2w的连接，足够了。另一方面相对与单线程的select，单一连接可读的时候，还可以减少循环扫描fd_set的次数。单线程下要扫描所有fd_set（如果再最后），该模型下，只需要扫描所在线程的fd_set就可。<br><span style="COLOR: red">（2）accept函数在多路复用函数之前，与（1）的差别在于，主线程不直接与从线程通过管道通讯，而是将获取的fd放入另一缓存线程的线程消息队列，缓存线程读消息队列，然后通过管道与从线程通讯。<br></span>目的在主线程中减少系统调用，加快accept的处理，避免连接爆发情况下的拒绝连接。<br><span style="COLOR: red">（3）多路复用函数在accept之前</span><span style="COLOR: red">。</span>多路复用函数返回，如果可读的是serverfd，则accept，其它则read，后处理业务，这是多路复用通用的模型，也是经典的reactor模型。<br><span style="COLOR: red">（</span><span style="COLOR: red">4）连接在单独线程中处理。<br><span style="COLOR: #000000">以上（1）（2）（3）都可以在检测到cliendfd可读的时候，把描述符写入另一线程（也可以是线程池）的线程消息队列，另一线程（或线程池）负责read，后处理业务。</span></span><br><span style="COLOR: #ff0000">（5）业务线程独立，下面的网络层读取结束后通知业务线程。</span><br>以上（1）（2）（3）（4）中都可以将业务线程（可以是线程池）独立，事先告之（1）、（2）、（3）、（4）中read所在线程（上面1、2、4都可以是线程池），需要读取的字符串结束标志或者需要读取的字符串个数，读取结束，则将clientfd/buffer指针放入业务线程的线程消息队列，业务线程读取消息队列处理业务。这也就是经典的proactor模拟。<br><span style="COLOR: #ff0000">总结：</span>模型（1）是拓展select处理能力不错选择；模型（2）是模型（1）在爆发连接下的调整版本；模型（3）是经典的reactor，epoll在该模型下性能就已经很好，而select/poll仍然存在爆发连接的拒绝连接情况；模型（4）（5）则是方便业务处理，对模型（3）进行多线程调整的版本。带有复杂业务处理的情况下推荐模型（5）。根据测试显示，使用epoll的时候，模型（1）（2）相对（3）没有明显的性能优势，（1）由于主线程两次的系统调用，反而性能下降。<br><strong>3、实时信号模型：</strong><br>使用fcntl的F_SETSIG操作，把描述符可读的信号由不可靠的SIGIO(SYSTEM V)或者SIGPOLL(BSD)换成可靠信号。即可成为替代多路复用的方式。优于select/poll，特别是在大量死连接存在的情况下，但不及epoll。<br><strong>四、多进程的参与的方式</strong><br><span style="COLOR: red">（1）fork模型。fork后所有进程直接在accept阻塞。</span>以上主线程在accept阻塞的都可以在accept前fork为多进程。同样面临惊群问题。<br><span style="COLOR: red">（2）fork模型。fork后所有进程阻塞在accept前的线程锁处。</span>同线程中一样避免不支持所有进程直接阻塞在accept或者惊群问题，所有进程阻塞在共享内存上实现的线程互斥锁。<br><span style="COLOR: red">（3）业务和网络层分离为不同进程模型。</span>这个模型可能是受unix简单哲学的影响，一个进程完成一件事情，复杂的事情通过多个进程结合管道完成。我见过进程方式的商业协议栈实现。自己暂时还没有写该模型的示例程序测试对比性能。<br><span style="COLOR: red">（4）均衡负载模型。</span>起多个进程绑定到不同的服务端口，前端部署lvs等均衡负载系统，暴露一个网络地址，后端映射到不同的进程，实现可扩展的多进程方案。<br><span style="COLOR: red">总结：</span>个人认为（1）（2）没什么意义。（3）暂不评价。（4）则是均衡负载方案，和以上所有方案不冲突。<br>以上模型的代码示例以及性能对比后面给出。<br></p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/45061.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-03-21 17:16 <a href="http://www.cppblog.com/CppExplore/archive/2008/03/21/45061.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 线程（二）</title><link>http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Thu, 20 Mar 2008 06:33:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/44949.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/44949.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/44949.html</trackback:ping><description><![CDATA[<p>作者：CppExplore&nbsp; 网址：<a href="http://www.cppblog.com/CppExplore/">http://www.cppblog.com/CppExplore/</a><br>为了后面写的《网络模型（二）》，多写一篇关于线程的。线程使用涉及的主要数据结构以及应用框架可以参考<a href="http://www.cppblog.com/CppExplore/archive/2008/01/15/41175.html">http://www.cppblog.com/CppExplore/archive/2008/01/15/41175.html</a>。本文的主要目的是给出linux下实用的线程消息队列实现。<br><strong>一、linux上线程相关的操作有下面几种：</strong><br>（1）pthread_t类型的创建、属性创建设置等。<br>这类具体可以:man pthread_creat; man pthread_attr_init;man pthread_detach;man pthread_join;等查看<br>（2）pthread_mutex_t类型的操作。<br>这类具体可以: man pthread_mutex_init可以看到所有相关的操作。<br>（3）pthread_cond_t类型的操作。同样：man pthread_cond_init。pthread_cond_t的wait和signal操作一定要和pthread_mutex_t的lock、unlock配合使用。类似于此：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">pthread_mutex_t&nbsp;mux</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">PTHREAD_MUTEX_INITIALIZER;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>pthread_cond_t&nbsp;cond</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">PTHREAD_COND_INITIALIZER;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">wait操作：</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">pthread_mutex_lock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>pthread_cond_wait(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">cond,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">睡眠前将内部会执行pthread_mutex_unlock，醒来时内部会执行pthread_mutex_lock</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">pthread_mutex_unlock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">signal操作</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000">pthread_mutex_lock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>pthread_cond_signal(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">cond);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>pthread_mutex_unlock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>（4）sem_t类型的操作。同样:man sem_init 这个系列一般是用不到的，太重量级了，也是最强大的一种。</p>
<p><strong>二、linux2.6内核的线程库。</strong>2.6内核的默认安装的是redhat公司的NPTL（原生posix线程库），以前内核安装的是LinuxThreads库，两者的简单介绍可以看<a href="http://www.ibm.com/developerworks/cn/linux/l-threading.html">http://www.ibm.com/developerworks/cn/linux/l-threading.html</a>。不过对于应用者，分析两者的区别和优劣也没什么大意义。这里特别提下NPTL的futex机制。借助该机制，pthread_mutex的性能大大提高，只要不进入竞争态，进程就不会陷入内核态。这点可以自己写示例程序，通过strace -c 跟踪进程的系统调用得以证实，另外还可以证实总是进入内核态的操作有pthread_cond_signal和sem_post。</p>
<p><strong>三、实用的线程消息队列实现。</strong>下面设计一个具有线程消息队列的线程封装类。通过上面的分析，我们可以有如下结论：<br>（1）减少pthread_cond_signal和sem_post的调用，只在有必要的时候调用； <br>（2）尽量避免pthread_mutex进入竞争态。增大消息队列的大小，可以有效减少竞态条件的出现。</p>
<p>下面给出一个实用的线程消息队列的实现类，这个类也将是以后《网络模型》文章中用到的线程消息队列类，代码注释请看对私有属性的注释：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;CThreadQueue<br><img id=Codehighlighter1_19_1863_Open_Image onclick="this.style.display='none'; Codehighlighter1_19_1863_Open_Text.style.display='none'; Codehighlighter1_19_1863_Closed_Image.style.display='inline'; Codehighlighter1_19_1863_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_19_1863_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_19_1863_Closed_Text.style.display='none'; Codehighlighter1_19_1863_Open_Image.style.display='inline'; Codehighlighter1_19_1863_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_19_1863_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_19_1863_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;CThreadQueue(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;queueSize</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">1024</span><span style="COLOR: #000000">):<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sizeQueue(queueSize),lput(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">),lget(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">),nFullThread(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">),nEmptyThread(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">),nData(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_157_317_Open_Image onclick="this.style.display='none'; Codehighlighter1_157_317_Open_Text.style.display='none'; Codehighlighter1_157_317_Closed_Image.style.display='inline'; Codehighlighter1_157_317_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_157_317_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_157_317_Closed_Text.style.display='none'; Codehighlighter1_157_317_Open_Image.style.display='inline'; Codehighlighter1_157_317_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_157_317_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_157_317_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_init(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_init(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">condGet,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_init(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">condPut,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)[sizeQueue];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;virtual&nbsp;</span><span style="COLOR: #000000">~</span><span style="COLOR: #000000">CThreadQueue()<br><img id=Codehighlighter1_351_382_Open_Image onclick="this.style.display='none'; Codehighlighter1_351_382_Open_Text.style.display='none'; Codehighlighter1_351_382_Closed_Image.style.display='inline'; Codehighlighter1_351_382_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_351_382_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_351_382_Closed_Text.style.display='none'; Codehighlighter1_351_382_Open_Image.style.display='inline'; Codehighlighter1_351_382_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_351_382_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_351_382_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete[]&nbsp;buffer;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;getq()<br><img id=Codehighlighter1_406_1015_Open_Image onclick="this.style.display='none'; Codehighlighter1_406_1015_Open_Text.style.display='none'; Codehighlighter1_406_1015_Closed_Image.style.display='inline'; Codehighlighter1_406_1015_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_406_1015_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_406_1015_Closed_Text.style.display='none'; Codehighlighter1_406_1015_Open_Image.style.display='inline'; Codehighlighter1_406_1015_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_406_1015_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_406_1015_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">data;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_lock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(lget</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">lput</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">nData</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">此处循环判断的原因如下：假设2个线程在getq阻塞，然后两者都被激活，而其中一个线程运行比较块，快速消耗了2个数据，另一个线程醒来的时候已经没有新数据可以消耗了。另一点，man pthread_cond_wait可以看到，该函数可以被信号中断返回，此时返回EINTR。为避免以上任何一点，都必须醒来后再次判断睡眠条件。更正：pthread_cond_wait是信号安全的系统调用，不会被信号中断。</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_590_707_Open_Image onclick="this.style.display='none'; Codehighlighter1_590_707_Open_Text.style.display='none'; Codehighlighter1_590_707_Closed_Image.style.display='inline'; Codehighlighter1_590_707_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_590_707_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_590_707_Closed_Text.style.display='none'; Codehighlighter1_590_707_Open_Image.style.display='inline'; Codehighlighter1_590_707_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_590_707_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_590_707_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nEmptyThread</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_wait(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">condGet,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nEmptyThread</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">buffer[lget</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nData</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(lget</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">sizeQueue)<br><img id=Codehighlighter1_804_834_Open_Image onclick="this.style.display='none'; Codehighlighter1_804_834_Open_Text.style.display='none'; Codehighlighter1_804_834_Closed_Image.style.display='inline'; Codehighlighter1_804_834_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_804_834_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_804_834_Closed_Text.style.display='none'; Codehighlighter1_804_834_Open_Image.style.display='inline'; Codehighlighter1_804_834_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_804_834_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_804_834_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lget</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(nFullThread)&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">必要时才进行signal操作，勿总是signal</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_895_952_Open_Image onclick="this.style.display='none'; Codehighlighter1_895_952_Open_Text.style.display='none'; Codehighlighter1_895_952_Closed_Image.style.display='inline'; Codehighlighter1_895_952_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_895_952_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_895_952_Closed_Text.style.display='none'; Codehighlighter1_895_952_Open_Image.style.display='inline'; Codehighlighter1_895_952_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_895_952_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_895_952_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_signal(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">condPut);&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_unlock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;data;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;putq(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">data)<br><img id=Codehighlighter1_1047_1479_Open_Image onclick="this.style.display='none'; Codehighlighter1_1047_1479_Open_Text.style.display='none'; Codehighlighter1_1047_1479_Closed_Image.style.display='inline'; Codehighlighter1_1047_1479_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1047_1479_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1047_1479_Closed_Text.style.display='none'; Codehighlighter1_1047_1479_Open_Image.style.display='inline'; Codehighlighter1_1047_1479_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1047_1479_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1047_1479_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_lock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(lput</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">lget</span><span style="COLOR: #000000">&amp;&amp;</span><span style="COLOR: #000000">nData)<br><img id=Codehighlighter1_1124_1235_Open_Image onclick="this.style.display='none'; Codehighlighter1_1124_1235_Open_Text.style.display='none'; Codehighlighter1_1124_1235_Closed_Image.style.display='inline'; Codehighlighter1_1124_1235_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1124_1235_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1124_1235_Closed_Text.style.display='none'; Codehighlighter1_1124_1235_Open_Image.style.display='inline'; Codehighlighter1_1124_1235_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1124_1235_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1124_1235_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nFullThread</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_wait(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">condPut,</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nFullThread</span><span style="COLOR: #000000">--</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buffer[lput</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">data;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;nData</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(lput</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">sizeQueue)<br><img id=Codehighlighter1_1319_1349_Open_Image onclick="this.style.display='none'; Codehighlighter1_1319_1349_Open_Text.style.display='none'; Codehighlighter1_1319_1349_Closed_Image.style.display='inline'; Codehighlighter1_1319_1349_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1319_1349_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1319_1349_Closed_Text.style.display='none'; Codehighlighter1_1319_1349_Open_Image.style.display='inline'; Codehighlighter1_1319_1349_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1319_1349_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1319_1349_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lput</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(nEmptyThread)<br><img id=Codehighlighter1_1384_1437_Open_Image onclick="this.style.display='none'; Codehighlighter1_1384_1437_Open_Text.style.display='none'; Codehighlighter1_1384_1437_Closed_Image.style.display='inline'; Codehighlighter1_1384_1437_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1384_1437_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1384_1437_Closed_Text.style.display='none'; Codehighlighter1_1384_1437_Open_Image.style.display='inline'; Codehighlighter1_1384_1437_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1384_1437_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1384_1437_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_signal(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">condGet);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_unlock(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">mux);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pthread_mutex_t&nbsp;mux;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_t&nbsp;condGet;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pthread_cond_t&nbsp;condPut;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;buffer;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">循环消息队列</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;sizeQueue;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">队列大小</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;lput;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">location&nbsp;put&nbsp;&nbsp;放数据的指针偏移</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;lget;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">location&nbsp;get&nbsp;&nbsp;取数据的指针偏移</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nFullThread;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">队列满，阻塞在putq处的线程数</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nEmptyThread;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">队列空，阻塞在getq处的线程数</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;nData;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">队列中的消息个数，主要用来判断队列空还是满</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></span><span style="COLOR: #000000">}</span></span><span style="COLOR: #000000">;</span></div>
<p>&nbsp;</p>
<p>下面给出这个线程消息队列的一个使用举例：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">pthread.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">unistd.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">stdlib.h</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>CThreadQueue&nbsp;queue;//使用的时候给出稍大的CThreadQueue初始化参数，可以减少进入内核态的操作。</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;produce(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;arg)<br><img id=Codehighlighter1_145_243_Open_Image onclick="this.style.display='none'; Codehighlighter1_145_243_Open_Text.style.display='none'; Codehighlighter1_145_243_Closed_Image.style.display='inline'; Codehighlighter1_145_243_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_145_243_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_145_243_Closed_Text.style.display='none'; Codehighlighter1_145_243_Open_Image.style.display='inline'; Codehighlighter1_145_243_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_145_243_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_145_243_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;pthread_detach(pthread_self());<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">++&lt;</span><span style="COLOR: #000000">100</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_207_241_Open_Image onclick="this.style.display='none'; Codehighlighter1_207_241_Open_Text.style.display='none'; Codehighlighter1_207_241_Closed_Image.style.display='inline'; Codehighlighter1_207_241_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_207_241_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_207_241_Closed_Text.style.display='none'; Codehighlighter1_207_241_Open_Image.style.display='inline'; Codehighlighter1_207_241_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_207_241_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_207_241_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;queue.putq((</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)i</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">consume(</span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">arg)<br><img id=Codehighlighter1_270_355_Open_Image onclick="this.style.display='none'; Codehighlighter1_270_355_Open_Text.style.display='none'; Codehighlighter1_270_355_Closed_Image.style.display='inline'; Codehighlighter1_270_355_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_270_355_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_270_355_Closed_Text.style.display='none'; Codehighlighter1_270_355_Open_Image.style.display='inline'; Codehighlighter1_270_355_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_270_355_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_270_355_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;data;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_294_353_Open_Image onclick="this.style.display='none'; Codehighlighter1_294_353_Open_Text.style.display='none'; Codehighlighter1_294_353_Closed_Image.style.display='inline'; Codehighlighter1_294_353_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_294_353_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_294_353_Closed_Text.style.display='none'; Codehighlighter1_294_353_Open_Image.style.display='inline'; Codehighlighter1_294_353_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_294_353_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_294_353_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">)(queue.getq());<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">data=%d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,data)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_368_515_Open_Image onclick="this.style.display='none'; Codehighlighter1_368_515_Open_Text.style.display='none'; Codehighlighter1_368_515_Closed_Image.style.display='inline'; Codehighlighter1_368_515_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_368_515_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_368_515_Closed_Text.style.display='none'; Codehighlighter1_368_515_Open_Image.style.display='inline'; Codehighlighter1_368_515_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_368_515_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_368_515_Open_Text><span style="COLOR: #000000">{&nbsp;&nbsp;&nbsp;&nbsp;pthread_t&nbsp;pid;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">++&lt;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pid,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,produce,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">(i</span><span style="COLOR: #000000">++&lt;</span><span style="COLOR: #000000">3</span><span style="COLOR: #000000">)<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pthread_create(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pid,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,consume,</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;sleep(</span><span style="COLOR: #000000">300</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<img src ="http://www.cppblog.com/CppExplore/aggbug/44949.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-03-20 14:33 <a href="http://www.cppblog.com/CppExplore/archive/2008/03/20/44949.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 网络模型（一）基础篇</title><link>http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Fri, 14 Mar 2008 09:36:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/44509.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/44509.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/44509.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 作者：CppExplore 地址：http://www.cppblog.com/CppExplore/全文针对linux环境。tcp/udp两种server种，tcp相对较复杂也相对比较常用。本文就从tcp server开始讲起。先从基本说起，看一个单线程的网络模型，处理流程如下：socket--&gt;bind--&gt;listen--&gt;[accept--&gt;read--&g...&nbsp;&nbsp;<a href='http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html'>阅读全文</a><img src ="http://www.cppblog.com/CppExplore/aggbug/44509.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-03-14 17:36 <a href="http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 内存管理（三）</title><link>http://www.cppblog.com/CppExplore/archive/2008/02/20/42986.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Wed, 20 Feb 2008 07:09:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/02/20/42986.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/42986.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/02/20/42986.html#Feedback</comments><slash:comments>21</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/42986.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/42986.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 地址：<a href="http://www.cppblog.com/CppExplore/(2)boost::pool">http://www.cppblog.com/CppExplore/<span style="COLOR: red"><br>(2)boost::pool</a></span><span style="COLOR: red">系列</span>。boost的内存池最低层是simple_segregated_storage，类似于Loki中的chunk，在其中申请释放block（boost中把block称为chunk，晕死，这里还是称其为block）采用了和loki的chunk中同样的算法，不同的是simple_segregated_storage使用void*保存block的块序号，loki中使用char，因此boost中的simple_segregated_storage没有255的上限限制，自然也就不需要再其上再封装一层类似与FixedAllocator的层面。另boost没有屏蔽块的大小，直接提供定长的接口给用户，省掉了SmallObjAllocator层面。因此boost的内存池申请释放block的时间复杂度都是O(1)（object_pool和pool_allocator除外），另避免的小内存的浪费，同时boost不能象loki那样在将block归还给内存池的时候根据chunk的空闲数量释放内存归还给系统，只能显式调用释放内存函数或者等内存池销毁的时候，基本上和内存池生命周期内永不释放没什么区别。<br>&nbsp;&nbsp;&nbsp; boost的最低层是simple_segregated_storage,主要算法和loki中的chunk一样，不多说了。这里说下影响上层接口的两类实现：add_block/malloc/free、add_ordered_block/malloc/ordered_free，两种低层实现造成boost上层设计的成功与失败,前者效率高，和loki一样直接增加释放,时间复杂度O(1)，后者扫描排序，时间复杂度O(n)。<br>&nbsp;&nbsp;&nbsp; boost提供了四种内存池模型供使用：pool、object_pool、singleton_pool、pool_allocator/fast_pool_allocator。<br><span style="COLOR: red">1）pool</span><br>基本的定长内存池</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">pool</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">pool.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>typedef&nbsp;struct&nbsp;student_st<br><img id=Codehighlighter1_57_89_Open_Image onclick="this.style.display='none'; Codehighlighter1_57_89_Open_Text.style.display='none'; Codehighlighter1_57_89_Closed_Image.style.display='inline'; Codehighlighter1_57_89_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_57_89_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_57_89_Closed_Text.style.display='none'; Codehighlighter1_57_89_Open_Image.style.display='inline'; Codehighlighter1_57_89_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_57_89_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_57_89_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;name[</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;age;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">CStudent;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_111_261_Open_Image onclick="this.style.display='none'; Codehighlighter1_111_261_Open_Text.style.display='none'; Codehighlighter1_111_261_Closed_Image.style.display='inline'; Codehighlighter1_111_261_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_111_261_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_111_261_Closed_Text.style.display='none'; Codehighlighter1_111_261_Open_Image.style.display='inline'; Codehighlighter1_111_261_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_111_261_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_111_261_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;boost::pool</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #000000">&nbsp;student_pool(sizeof(CStudent));<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;obj</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)student_pool.malloc();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;student_pool.free(obj);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p>&nbsp;&nbsp;&nbsp; pool的模版参数只有一个分配子类型，boost提供了两种default_user_allocator_new_delete/default_user_allocator_malloc_free，指明申请释放内存的时候使用new/delete，还是malloc/free，默认是default_user_allocator_new_delete。构造函数有2个参数：nrequested_size,nnext_size。nrequested_size是block的大小（因为void*保存序号，因此boost内置了block的最小值，nrequested_size过小则取内置值），nnext_size是simple_segregated_storage中内存不足的时候，申请的block数量，默认是32。最全面的实例化pool类似这样：boost::pool&lt;boost::default_user_allocator_malloc_free&gt; student_pool(sizeof(CStudent),255);<br>&nbsp;&nbsp;&nbsp; pool提供的函数主要有：<br>
<table style="WIDTH: 730px; BORDER-COLLAPSE: collapse; HEIGHT: 151px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>malloc/free&nbsp;</td>
            <td>基于add_block/malloc/free实现，高效<br></td>
        </tr>
        <tr>
            <td>ordered_malloc/ordered_free </td>
            <td>基于add_ordered_block/malloc/ordered_free实现，在pool中无任何意义，切勿使用。<br></td>
        </tr>
        <tr>
            <td>release_memory/purge_memory</td>
            <td>前者释放池中未使用内存，后者释放池中所有内存。另池析构也会释放内存<br></td>
        </tr>
    </tbody>
</table>
<span style="COLOR: red"><br>2）object_pool</span><br>对象内存池，这是最失败的一个内存池设计。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">pool</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">object_pool.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img id=Codehighlighter1_46_97_Open_Image onclick="this.style.display='none'; Codehighlighter1_46_97_Open_Text.style.display='none'; Codehighlighter1_46_97_Closed_Image.style.display='inline'; Codehighlighter1_46_97_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_46_97_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_46_97_Closed_Text.style.display='none'; Codehighlighter1_46_97_Open_Image.style.display='inline'; Codehighlighter1_46_97_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;A</span><span id=Codehighlighter1_46_97_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_46_97_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img id=Codehighlighter1_71_72_Open_Image onclick="this.style.display='none'; Codehighlighter1_71_72_Open_Text.style.display='none'; Codehighlighter1_71_72_Closed_Image.style.display='inline'; Codehighlighter1_71_72_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_71_72_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_71_72_Closed_Text.style.display='none'; Codehighlighter1_71_72_Open_Image.style.display='inline'; Codehighlighter1_71_72_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;A():data_(</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">)</span><span id=Codehighlighter1_71_72_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_71_72_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;data_;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_111_223_Open_Image onclick="this.style.display='none'; Codehighlighter1_111_223_Open_Text.style.display='none'; Codehighlighter1_111_223_Closed_Image.style.display='inline'; Codehighlighter1_111_223_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_111_223_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_111_223_Closed_Text.style.display='none'; Codehighlighter1_111_223_Open_Image.style.display='inline'; Codehighlighter1_111_223_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_111_223_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_111_223_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;boost::object_pool</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">A</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;obj_pool;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;A&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;pA</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">obj_pool.construct();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;obj_pool.destroy(pA);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>&nbsp;&nbsp;&nbsp; object_pool继承至pool，有两个模版参数，第一个就是对象类型，第二个是分配子类型，默认同pool是default_user_allocator_new_delete。构造函数参数只有nnext_size，意义以及默认值同pool。最全面的实例化object_pool类似这样：boost::pool&lt;A,boost::default_user_allocator_malloc_free&gt; obj_pool(255);<br>object_pool提供的函数主要有（继承至父类的略）：
<table style="WIDTH: 756px; BORDER-COLLAPSE: collapse; HEIGHT: 137px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>malloc/free</td>
            <td>复写pool的malloc/free，add_ordered_block/malloc/ordered_free实现</td>
        </tr>
        <tr>
            <td>construct/destroy</td>
            <td>基于本类的malloc/free实现，额外调用默认构造函数和默认析构函数。</td>
        </tr>
        <tr>
            <td>~object_pool </td>
            <td>单独拿出这个说下，若析构的时候有对象未被destroy，可以检测到，释放内存前对其执行destroy</td>
        </tr>
    </tbody>
</table>
&nbsp;&nbsp;&nbsp; 为什么boost::object_pool要设计成这样？能调用构造函数和析构函数显然不是boost::object_pool类设计的出发点，因为构造函数只能执行默认构造函数（<span style="COLOR: red">首次发表错误：可以调用任意的构造函数，参见代码文件：boost/pool/detail/pool_construct.inc和boost/pool/detail/pool_construct_simple.inc，感谢eXile指正</span>），近似于无，它的重点是内存释放时候的清理工作，这个工作默认的析构函数就足够了。apr_pool内存池中就可以注册内存清理函数，在释放内存的时刻执行关闭文件描述符、关闭socket等操作。boost::object_pool也想实现同样的功能，因此设计了destroy这个函数，而同时为了防止用户遗漏掉这个调用，而又在内存池析构的时候进行了检测回收。为了这个目的而又不至于析构object_pool的时间复杂度是O(n平方），boost::object_pool付出了沉重的代价，在每次的destoy都执行排序功能，时间复杂度O(n),最后析构的时间复杂度是O(n)，同样为了这个目的，从simple_segregated_storage增加了add_ordered_block/ordered_free，pool增加了ordered_malloc/ordered_free等累赘多余的功能。<br>&nbsp;&nbsp;&nbsp; 基于上面讨论的原因，boost::object_pool被设计成了现在的样子，成了一个鸡肋类。类的设计者似乎忘记了内存池使用的初衷，忘记了内存池中内存申请释放的频率很高，远远大于内存池对象的析构。如果你依然想使用类似于此的内存清理功能，可以在boost::object_pool上修改，不复写malloc/free即可，重写object_pool的析构，简单释放内存就好，因此析构object_pool前不要忘记调用destroy，这也是使用placement new默认遵守的规则，或者保持以前的析构函数，牺牲析构时的性能。placement new的作用是为已经申请好的内存调用构造函数，使用流程为（1）申请内存buf（2）调用placement new：new(buf)construtor()（3）调用析构destructor()（4）释放内存buf。#include&lt;new&gt;可以使用placement new。<br><span style="COLOR: red">3）singleton_pool</span><br>pool的加锁版本。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">pool</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">singleton_pool.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>typedef&nbsp;struct&nbsp;student_st<br><img id=Codehighlighter1_67_99_Open_Image onclick="this.style.display='none'; Codehighlighter1_67_99_Open_Text.style.display='none'; Codehighlighter1_67_99_Closed_Image.style.display='inline'; Codehighlighter1_67_99_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_67_99_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_67_99_Closed_Text.style.display='none'; Codehighlighter1_67_99_Open_Image.style.display='inline'; Codehighlighter1_67_99_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_67_99_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_67_99_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;name[</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;age;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">CStudent;<br><img id=Codehighlighter1_143_144_Open_Image onclick="this.style.display='none'; Codehighlighter1_143_144_Open_Text.style.display='none'; Codehighlighter1_143_144_Closed_Image.style.display='inline'; Codehighlighter1_143_144_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_143_144_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_143_144_Closed_Text.style.display='none'; Codehighlighter1_143_144_Open_Image.style.display='inline'; Codehighlighter1_143_144_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top>typedef&nbsp;struct&nbsp;singleton_pool_tag</span><span id=Codehighlighter1_143_144_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_143_144_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000">singleton_pool_tag;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_176_344_Open_Image onclick="this.style.display='none'; Codehighlighter1_176_344_Open_Text.style.display='none'; Codehighlighter1_176_344_Closed_Image.style.display='inline'; Codehighlighter1_176_344_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_176_344_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_176_344_Closed_Text.style.display='none'; Codehighlighter1_176_344_Open_Image.style.display='inline'; Codehighlighter1_176_344_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_176_344_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_176_344_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;typedef&nbsp;boost::singleton_pool</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">singleton_pool_tag,sizeof(CStudent)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;&nbsp;global;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">const</span><span style="COLOR: #000000">&nbsp;df</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">(CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)global::malloc();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;global::free(df);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p>&nbsp;&nbsp;&nbsp; singleton_pool为单例类，是对pool的加锁封装，适用于多线程环境，其中所有函数都是静态类型。它的模版参数有5个，tag：标记而已，无意义；RequestedSize：block的长度；UserAllocator：分配子，默认还是default_user_allocator_new_delete；Mutex：锁机制，默认值最终依赖于系统环境，linux下是pthread_mutex，它是对pthread_mutex_t的封装；NextSize：内存不足的时候，申请的block数量，默认是32。最全面的使用singleton_pool类似这样：typedef boost::singleton_pool&lt;singleton_pool_tag,sizeof(CStudent),default_user_allocator_new_delete,details::pool::default_mutex,200&gt;&nbsp; global;<br>&nbsp;&nbsp;&nbsp; 它暴露的函数和pool相同。<br><span style="COLOR: red">4）pool_allocator/fast_pool_allocator</span><br>&nbsp;&nbsp;&nbsp; stl::allocator的替换方案。两者都是基于singleton_pool实现，实现了stl::allocator要求的接口规范。两者的使用相同，区别在于pool_allocator的实现调用ordered_malloc/ordered_free，fast_pool_allocator的实现调用malloc/free，因此推荐使用后者。</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">pool</span><span style="COLOR: #000000">/</span><span style="COLOR: #000000">pool_alloc.hpp</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">vector</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>typedef&nbsp;struct&nbsp;student_st<br><img id=Codehighlighter1_82_110_Open_Image onclick="this.style.display='none'; Codehighlighter1_82_110_Open_Text.style.display='none'; Codehighlighter1_82_110_Closed_Image.style.display='inline'; Codehighlighter1_82_110_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_82_110_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_82_110_Closed_Text.style.display='none'; Codehighlighter1_82_110_Open_Image.style.display='inline'; Codehighlighter1_82_110_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_82_110_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_82_110_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;name[</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">];<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;age;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">CStudent;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_133_359_Open_Image onclick="this.style.display='none'; Codehighlighter1_133_359_Open_Text.style.display='none'; Codehighlighter1_133_359_Closed_Image.style.display='inline'; Codehighlighter1_133_359_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_133_359_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_133_359_Closed_Text.style.display='none'; Codehighlighter1_133_359_Open_Image.style.display='inline'; Codehighlighter1_133_359_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_133_359_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_133_359_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;std::vector</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">,boost::fast_pool_allocator</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">CStudent&nbsp;</span><span style="COLOR: #000000">*&gt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">&nbsp;v(</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">pObj</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;CStudent();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;v[</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">]</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">pObj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;boost::singleton_pool</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">boost::fast_pool_allocator_tag,sizeof(CStudent&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">&gt;</span><span style="COLOR: #000000">::purge_memory();&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>&nbsp;&nbsp;&nbsp; fast_pool_allocator的模版参数有四个：类型，分配子，锁类型，内存不足时的申请的block数量，后三者都有默认值，不再说了。它使用的singleton_pool的tag是boost::fast_pool_allocator_tag。<br><span style="COLOR: red">评价：boost::pool小巧高效，多多使用，多线程环境下使用boost::singleton_pool，不要使用两者的ordered_malloc/ordered_free函数。boost::object_pool不建议使用，可以改造后使用。pool_allocator/fast_pool_allocator推荐使用后者。</span></p>
<br>未完 待续.................... 不过这个主题暂时不写了 等有时间了 
<img src ="http://www.cppblog.com/CppExplore/aggbug/42986.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-02-20 15:09 <a href="http://www.cppblog.com/CppExplore/archive/2008/02/20/42986.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原创】技术系列之 内存管理（二）</title><link>http://www.cppblog.com/CppExplore/archive/2008/02/19/42952.html</link><dc:creator>cppexplore</dc:creator><author>cppexplore</author><pubDate>Tue, 19 Feb 2008 09:30:00 GMT</pubDate><guid>http://www.cppblog.com/CppExplore/archive/2008/02/19/42952.html</guid><wfw:comment>http://www.cppblog.com/CppExplore/comments/42952.html</wfw:comment><comments>http://www.cppblog.com/CppExplore/archive/2008/02/19/42952.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cppblog.com/CppExplore/comments/commentRss/42952.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/CppExplore/services/trackbacks/42952.html</trackback:ping><description><![CDATA[<p>作者：CppExplore 地址：<a href="http://www.cppblog.com/CppExplore/">http://www.cppblog.com/CppExplore/</a><span style="COLOR: red"><br>2、定长内存池。</span>典型的实现有LOKI、BOOST。特点是为不同类型的数据结构分别创建内存池，需要内存的时候从相应的内存池中申请内存，优点是可以在使用完毕立即把内存归还池中，可以更为细粒度的控制内存块。<br>&nbsp;&nbsp;&nbsp; 与变长的相比，这种类型的内存池更加通用，另一方面对于大量不同的数据类型环境中，会浪费不少内存。但一般系统主要的数据结构都不会很多，并且都是重复申请释放使用，这种情况下，定长内存池的这点小缺点可以忽略了。<br><span style="COLOR: red"><strong style="COLOR: #000000">(1)Loki::SmallObject。</strong></span>Andrei Alexandrescu的《Modern C++ Design》第四章节已经进行了详细的描述，尽管和当前的loki版本实现有出入，还是了解Loki::SmallObject的最佳文字讲解，结合最新的loki源码，足够了。这里我再罗唆一下。先举例看下使用：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">loki/SmallObj.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">class</span><span style="COLOR: #000000">&nbsp;Small:</span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">&nbsp;&nbsp;Loki::SmallObject</span><span style="COLOR: #000000">&lt;&gt;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">继承SmallObject即可，所有都使用默认策略</span><span style="COLOR: #008000"><br><img id=Codehighlighter1_94_156_Open_Image onclick="this.style.display='none'; Codehighlighter1_94_156_Open_Text.style.display='none'; Codehighlighter1_94_156_Closed_Image.style.display='inline'; Codehighlighter1_94_156_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_94_156_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_94_156_Closed_Text.style.display='none'; Codehighlighter1_94_156_Open_Image.style.display='inline'; Codehighlighter1_94_156_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_94_156_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_94_156_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">public</span><span style="COLOR: #000000">:<br><img id=Codehighlighter1_132_133_Open_Image onclick="this.style.display='none'; Codehighlighter1_132_133_Open_Text.style.display='none'; Codehighlighter1_132_133_Closed_Image.style.display='inline'; Codehighlighter1_132_133_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_132_133_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_132_133_Closed_Text.style.display='none'; Codehighlighter1_132_133_Open_Image.style.display='inline'; Codehighlighter1_132_133_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;Small(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;data):data_(data)</span><span id=Codehighlighter1_132_133_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_132_133_Open_Text><span style="COLOR: #000000">{}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #0000ff">private</span><span style="COLOR: #000000">:<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;data_;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;main()<br><img id=Codehighlighter1_170_211_Open_Image onclick="this.style.display='none'; Codehighlighter1_170_211_Open_Text.style.display='none'; Codehighlighter1_170_211_Closed_Image.style.display='inline'; Codehighlighter1_170_211_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_170_211_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_170_211_Closed_Text.style.display='none'; Codehighlighter1_170_211_Open_Image.style.display='inline'; Codehighlighter1_170_211_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_170_211_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_170_211_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;Small&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">obj</span><span style="COLOR: #000000">=</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;Small(</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;delete&nbsp;obj;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p>使用valgrind执行可以证实new一个obj和多new几次，申请的内存都是4192。可以看出loki在使用层面非常简单。<br>&nbsp;&nbsp;&nbsp; loki的内存池分4层,从低向上依次是chunk、FixedAllocator、SmallObjAllocator、SmallObject。<br><span style="COLOR: red">1）chunk：</span>每个chunk管理一定数量（最大255，char型保存）的block，每个chunk中block的申请和释放，时间复杂度都是o(1)，非常快，实现算法非常精巧，boost::pool中也是采用的相同算法。<br>&nbsp;&nbsp;&nbsp; 这里简单说下这个算法：首次申请一块连续内存，pdata_指向该内存基址，依据block大小，划分成多个连续的block，每个block开头的第一个字节保存该block的顺序号，第一个是1，第二个是2，依次类推。另有一字节变量firstAvailableBlock_存储上次分配出的block序号，开始是0。<br>&nbsp;&nbsp;&nbsp; 分配block：返回pdata_ +firstAvailableBlock_*blocksize，同时firstAvailableBlock_赋值为该块的序列号。<br>&nbsp;&nbsp;&nbsp; 回收block：block指针假设为pblock，该块序列号赋值为firstAvailableBlock_，firstAvailableBlock_赋值为（pblock-pdata_ ）/blocksize即可。<br><span style="COLOR: red">2）FixedAllocator：</span>chunk中的block上限是255，不具有通用性，因此封装了一层，称为FixedAllocator，它保存了一个vector&lt;chunk&gt;，消除了单个chunk中block数目的上限限制。<br>&nbsp;&nbsp; FixedAllocator中的block申请：FixedAllocator中保存活动的chunk（上次有空闲空间的chunk），申请block的时候如果活动chunk有空闲快，直接申请，否则扫描vector，时间复杂度o(N),同时更新活动chunk。<br>&nbsp;&nbsp; FixedAllocator中的回收block：简单想，给定block回收到FixedAllocator，自然要扫描vector，以确认block属于哪个chunk，以便chunk回收。实际实现的时候，Loki针对应用场景进行了优化，一般使用都是批量使用，回收一般和申请顺序相同或者相反，因此FixedAllocator保存上次回收block的chunk指针，每次回收优先匹配这个chunk，匹配不上则以该chunk为中心，向两侧chunk顺序检测。<br>&nbsp;&nbsp; FixedAllocator带来的优点：上文提到的消除了block的上限限制。另一方面，可以以chunk为单位，把内存归还给操作系统。实际实现中防止刚释放的内存立即又被申请，是存在两个空闲chunk的时候才回收一个。这个特点，这里暂时归结为优点吧。实际使用中，回收多余内存个人认为是个缺点，意义并不是很大。<br>&nbsp;&nbsp; FixedAllocator带来的缺点：很明显，就是申请回收block的时间复杂度。<br><span style="COLOR: red">3）SmallObjAllocator：</span>截至到FixedAllocator层面blocksize都是定长。因此封装一层适用于任意长度的内存申请。SmallObjAllocator保存了一个FixedAllocator的数组pool_，存储拥有不同block长度的FixedAllocator。《Modern C++ Design》中描述该数组下标和存储的FixedAllocator的block长度无直接关系，从SmallObjAllocator申请以及回收block的时候二分查找找到对应的FixedAllocator再调用相应FixedAllocator的申请或者回收。当前最新版本的loki，已经抛弃了这种做法。当前SmallObjAllocator的构造函数有3个参数：chunksize，maxblocksize，alignsize。数组元素个数取maxblocksize除以alignsize的向上取整。每个FixedAllocator中实际的blocksize是（下标＋1）*alignsize。<br>&nbsp;&nbsp;&nbsp;&nbsp; SmallObjAllocator中block申请：依据block和alignsize的商直接取到数组pool_下标，使用相应的FixedAllocator申请。<br>&nbsp;&nbsp;&nbsp;&nbsp; SmallObjAllocator中回收block：根据block和alignsize的商直接找到相应的FixedAllocator回收。<br>&nbsp;&nbsp;&nbsp;&nbsp; 优点：差异化各种长度的对象申请，增强了易用性。<br>&nbsp;&nbsp;&nbsp;&nbsp; 缺点：《Modern C++ Design》中描述增加扫描的时间复杂度，当前版本的loki浪费内存。这也是进一步封装，屏蔽定长申请的细节，带来的负面效应。<br><span style="COLOR: red">4）SmallObject。</span>暴露给外部使用的一层。该层面秉承了《Modern C++ Design》开始引入的以设计策略类为最终目的，让用户在编译期选择设计策略，而不是提供框架限制用户的设计。这也是引入模版的一个层面。当前版本SmallObject有6个模版参数，第一个是线程策略，紧接着的三个正好是SmallObjAllocator层面的三个构造参数，下面的一个生存期策略，最后的是锁方式。<br>&nbsp;&nbsp;&nbsp; 这里说下SmallObjAllocator层面的三个默认参数值，分别是4096，256，4。意味着SmallObjAllocator层面有数组（256+4-1)/4=64个，数组存储的FixedAllocator中的chunksize一般都是4096（当4096&lt;=blocksize*255时候）字节（第一个chunk的申请推迟到首次使用的时候），各FixedAllocator中的chunk的blocksize依次是4、8......256，大于256字节的内存申请交给系统的malooc/new管理，数组中FixedAllocator中单个chunk中的blocknum依次是4096/4=824&gt;255取255、255......4096/256=16。如果这不能满足需求，请调用的时候显式赋值。<br>&nbsp;&nbsp;&nbsp; 当前loki提供了三种线程策略：<br>
<table style="WIDTH: 614px; BORDER-COLLAPSE: collapse; HEIGHT: 102px" cellSpacing=0 cellPadding=3 border=1>
    <tbody>
        <tr>
            <td>SingleThreaded </td>
            <td>单线程</td>
        </tr>
        <tr>
            <td>ObjectLevelLockable </td>
            <td>对象级别，一个对象一个锁</td>
        </tr>
        <tr>
            <td>ClassLevelLockable </td>
            <td>类级别，一个类一个锁，该类的所有对象共用该锁</td>
        </tr>
    </tbody>
</table>
</p>
<p>目前只提供了一种锁机制：Mutex<br>它的基类SmallObjectBase复写了new/delete操作子，因此直接继承SmallObject就可以象普通的类一样new/delete，并且从内存池分配内存。<br>&nbsp;&nbsp;&nbsp; SmalObject中block申请和释放都从一个全局的SmallObjAllocator单例进行。<br><span style="COLOR: red">评价：chunk层面限制了上限个数，导致了<font color=#ff0000>FixedAllocator层面出现，造成申请回收时间复杂度的提高，而以chunk为单位回收内存，在内存池的使用场景下意义并不是很大。SmallObjAllocator为了差异化变长内存的申请，对FixedAllocator进一步封装，引入了内存的浪费，不如去掉这个层面，直接提供给用户层面定长的接口。另一方面，loki已经进行了不少优化，尽可能让block申请释放的时间复杂度在绝大多数情况下都是O(1),而SmallObjAllocator中内存的浪费可以根据alignsize调整，即便是极端情况下，loki将chunk归还给系统又被申请出来，根据chunk中block的最大值看，也比不使用内存池的情况动态申请释放内存的次数减少了1/255。因此，loki是一个非常不错的小巧的内存池。</font></span></p>
<img src ="http://www.cppblog.com/CppExplore/aggbug/42952.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/CppExplore/" target="_blank">cppexplore</a> 2008-02-19 17:30 <a href="http://www.cppblog.com/CppExplore/archive/2008/02/19/42952.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>