﻿<?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++博客-wy-文章分类-ACE</title><link>http://www.cppblog.com/wy/category/5974.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 15:05:07 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 15:05:07 GMT</pubDate><ttl>60</ttl><item><title>一劳永逸的在VC下使用最小化MPC</title><link>http://www.cppblog.com/wy/articles/41170.html</link><dc:creator>鱼儿</dc:creator><author>鱼儿</author><pubDate>Tue, 15 Jan 2008 01:39:00 GMT</pubDate><guid>http://www.cppblog.com/wy/articles/41170.html</guid><wfw:comment>http://www.cppblog.com/wy/comments/41170.html</wfw:comment><comments>http://www.cppblog.com/wy/articles/41170.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wy/comments/commentRss/41170.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wy/services/trackbacks/41170.html</trackback:ping><description><![CDATA[一劳永逸的在VC下使用最小化MPC<br><br>MPC即，MakeProjectCreator，不知道的就的人可能用不上吧，费话不用多说，就<br><br>直接写步骤吧。<br><br>准备工作：<br>安装Winrar，用于下载后的文件进行解压缩。<br><br>安装Perl，可从 <a href="http://www.activestate.com/Products/ActivePerl/" target=_blank><u><font color=#0000ff>http://www.activestate.com/Products/ActivePerl/</font></u></a> 下载。<br><br>以上安装用默认的方式安装即可。<br><br>第一步: <br>&nbsp; &nbsp; 下载ACE源代&nbsp;&nbsp;(Obtaining ACE, TAO, and CIAO) <br>&nbsp; &nbsp;&nbsp; &nbsp;<a href="http://download.dre.vanderbilt.edu/" target=_blank><u><font color=#0000ff>http://download.dre.vanderbilt.edu/</font></u></a><br><br>&nbsp; &nbsp;&nbsp; &nbsp;下载最新的Beta版 (当前版本为5.6.1)&nbsp;&nbsp;<a href="http://download.dre.vanderbilt.e/" target=_blank><u><font color=#0000ff>http://download.dre.vanderbilt.e</font></u></a> ... +TAO+CIAO-5.6.1.zip<br><br>第二步<br>&nbsp; &nbsp; 解压缩<br>&nbsp; &nbsp; 介绍解压到 d:\ACE_wrappers<br><br>第三步<br>&nbsp; &nbsp;设置必要的环境变量<br>&nbsp; &nbsp;$(ACE_ROOT),在Windows下，环境变量为%ACE_ROOT%<br>&nbsp; &nbsp;&nbsp;&nbsp;%ACE_ROOT% = d:\ACE_wrappers<br>&nbsp; &nbsp;&nbsp;&nbsp;%TAO_ROOT%=%ACE_ROOT% \tao<br>&nbsp; &nbsp;&nbsp;&nbsp;%CIAO_ROOT%=%ACE_ROOT% \tao\CIAO<br>如果需要用到DDS，可也设置了。<br>&nbsp; &nbsp;%DDS_ROOT%= YOUR_DDS_DIR<br><br>&nbsp; &nbsp;&nbsp; &nbsp;其中，<br>&nbsp; &nbsp;%ACE_ROOT% = d:\ACE_wrappers 为必须，其它为可选。<br><br>&nbsp; &nbsp; 在%PATH%中，增加 %ACE_ROOT%\bin;%ACE_ROOT%\lib<br><br>第三步<br>&nbsp; &nbsp;&nbsp;&nbsp;创建,创建一目录，目录下建<br>&nbsp; &nbsp;helloworld.mpc<br>内容为<br>project(*):aceexe,mfc {<br>&nbsp;&nbsp;exename=*<br>&nbsp;&nbsp;requires += mfc<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;pch_header&nbsp; &nbsp;= stdafx.h<br>&nbsp;&nbsp;pch_source&nbsp; &nbsp;= stdafx.cpp<br>}<br><br><br>第四步：<br>&nbsp; &nbsp;&nbsp; &nbsp;创建文件 helloworld.cpp, helloworld.h<br><br>第五步：<br>&nbsp; &nbsp;&nbsp; &nbsp;用mwc.pl 创建工程文件<br><br>&nbsp; &nbsp;&nbsp; &nbsp;进入dos shell <br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;如果用的是vc2005，<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;进入helloworld目录<br>&nbsp; &nbsp;&nbsp; &nbsp;mwc.pl -type vc8 -features mfc=1<br>&nbsp; &nbsp; <br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;如果用的是vs2003，用vc71替vc8<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;如果用的是vc6, 用vc6替换vc8<br><br>第六步：<br>&nbsp; &nbsp;&nbsp; &nbsp;系统为你生成了helloworld.sln, helloworld.vcproj<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;开始享受 mpc吧<br><br>以后只要在helloworld目录中新增了文件，都需要重运行 <br>&nbsp; &nbsp;&nbsp; &nbsp; mwc.pl -type vc8 -features mfc=1<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;来更新helloworld.vcproj<br>
<img src ="http://www.cppblog.com/wy/aggbug/41170.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wy/" target="_blank">鱼儿</a> 2008-01-15 09:39 <a href="http://www.cppblog.com/wy/articles/41170.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ACE项目Makefile的编写</title><link>http://www.cppblog.com/wy/articles/41169.html</link><dc:creator>鱼儿</dc:creator><author>鱼儿</author><pubDate>Tue, 15 Jan 2008 01:36:00 GMT</pubDate><guid>http://www.cppblog.com/wy/articles/41169.html</guid><wfw:comment>http://www.cppblog.com/wy/comments/41169.html</wfw:comment><comments>http://www.cppblog.com/wy/articles/41169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wy/comments/commentRss/41169.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wy/services/trackbacks/41169.html</trackback:ping><description><![CDATA[　　关于编写使用ACE类库项目的Makefile的写法，在&lt;&lt;ACE Programmer's Guide&gt;&gt;一书中有详细的介绍(见2.5 How to build your applications),另外ACE包中的文档makefile-hints.html一节也对此作了一些介绍。这里介绍一种更为简单的方法，呵呵，因为已经有好心人为我们写出了自动生成工具。:-)<br>　　 不知道大家有没有注意到在$ACE_ROOT/bin下有两个Perl脚本mpc.pl,mwc.pl和一个叫MakeProjectCreator的目录。<br>　　 Project Creator <br>　　 mpc.pl这个脚本可以生成支持GNU Make或MS NMake的Makefile，也可以生成支持VC的dsp或者vcproj文件。这里我只简单介绍一下如何生成Makefile,其他的大家可以去看文档:-)<br>　　 mpc.pl需要读入一个以mpc为后缀的Project文档，该Project文档应当包含了生成makefile的基本信息。一个Project典型的mpc文档如下所示：<br>　　 project(project_name) : baseproject,anotherbaseproject{<br>　　 exename = foo<br>　　 includes += "."<br>　　 libpaths = directory<br>　　 Source_Files {<br>　　 file1.cpp<br>　　 file2.cpp<br>　　 .<br>　　 .<br>　　 fileN.cpp<br>　　 }<br>　　 Header_Files {<br>　　 file1.h<br>　　 file2.h<br>　　 .<br>　　 .<br>　　 fileN.h<br>　　 }<br>　　 }<br>　　 mpc.pl工具的Project配置文件采用一种继承的方式读取预先的设定应用到当前的项目。其中project_name是可选的，如果没写那么将缺省用当前目录代替。在Linux下生成可执行文件一般baseproject设为aceexe,若生成lib库则设为acelib.另外还有一些关键字如exename(指定生成可执行文件的名称)，sharedname(生成指定共享库的名称)等等。Source_Files 和 Header_Files段指定了该Project的源文件和头文件。其他关键字具体可以查看相关的文档。<br>　　 mpc.pl读取project的mpc文件，并联合在MakeProjectCreator/Config目录下的baseproject的配置文件baseprojectname.mpb以及MakeProjectCreator/template目录下各种平台工具的编译文件的模板（.mpt文件 ）以及缺省模板值文件（.mpd文件）生成指定项目的Makefile。<br>　　 Workspace Creator<br>　　 mwc.pl则是读入一个由.mwc文件生成一个workspace的编译文件。它的格式如下<br>　　 workspace(workspace_name) {<br>　　 file.mpc<br>　　 directory<br>　　 }<br>　　 mwc.pl将逐个读入指定的.mpc文件以及指定目录下所有的.mpc文件生成各个project的Makefile，并生成整个workspace的Makefile。<br>　　 <br>　　 另外这两个脚本都有丰富的参数可以用来改变模板中的一些默认值，有兴趣的话可以具体看看makeprojectcreator目录下的README和USAGE.<br>　　 以mpc.pl为例使用这两个脚本的命令行如下：<br>　　 mpc.pl -argv argv_values input_project.mpc //前提是$ACE_ROOT/bin在你的PATH中<br>　　 输出<br>　　 Makefile.project_name<br>　　 具体的例子我就不就不举了，ACE包的很多例子代码中都带有.mpc和.mwc文件可供大家参考。 <br>　　 知道他们是做什么用的之后，大家一切就豁然开朗了，呵呵我也就不再赘述了。
<img src ="http://www.cppblog.com/wy/aggbug/41169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wy/" target="_blank">鱼儿</a> 2008-01-15 09:36 <a href="http://www.cppblog.com/wy/articles/41169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Comparing Two High-Performance I/O Design Patterns</title><link>http://www.cppblog.com/wy/articles/40947.html</link><dc:creator>鱼儿</dc:creator><author>鱼儿</author><pubDate>Fri, 11 Jan 2008 02:39:00 GMT</pubDate><guid>http://www.cppblog.com/wy/articles/40947.html</guid><wfw:comment>http://www.cppblog.com/wy/comments/40947.html</wfw:comment><comments>http://www.cppblog.com/wy/articles/40947.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/wy/comments/commentRss/40947.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/wy/services/trackbacks/40947.html</trackback:ping><description><![CDATA[<span class=as>原文出处: <a href="http://www.artima.com/articles/io_design_patterns.html">http://www.artima.com/articles/io_design_patterns.html</a><br><br>by Alexander Libman with Vladimir Gilbourd</span><br><span class=pd>November 25, 2005</span><br>
<div class=summary>
<div class=summarytitle>Summary</div>
This article investigates and compares different design patterns of high performance TCP-based servers. In addition to existing approaches, it proposes a scalable single-codebase, multi-platform solution (with code examples) and describes its fine-tuning on different platforms. It also compares performance of Java, C# and C++ implementations of proposed and existing solutions. </div>
<p>System I/O can be blocking, or non-blocking synchronous, or non-blocking asynchronous [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>1</font></u></a>, <a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>2</font></u></a>]. Blocking I/O means that the calling system does not return control to the caller until the operation is finished. As a result, the caller is blocked and cannot perform other activities during that time. Most important, the caller thread cannot be reused for other request processing while waiting for the I/O to complete, and becomes a wasted resource during that time. For example, a <code>read()</code> operation on a socket in blocking mode will not return control if the socket buffer is empty until some data becomes available. </p>
<p>By contrast, a non-blocking synchronous call returns control to the caller immediately. The caller is not made to wait, and the invoked system immediately returns one of two responses: If the call was executed and the results are ready, then the caller is told of that. Alternatively, the invoked system can tell the caller that the system has no resources (no data in the socket) to perform the requested action. In that case, it is the responsibility of the caller may repeat the call until it succeeds. For example, a <code>read()</code> operation on a socket in non-blocking mode may return the number of read bytes or a special return code -1 with errno set to <code>EWOULBLOCK/EAGAIN</code>, meaning "not ready; try again later." </p>
<p>In a non-blocking asynchronous call, the calling function returns control to the caller immediately, reporting that the requested action was started. The calling system will execute the caller's request using additional system resources/threads and will notify the caller (by callback for example), when the result is ready for processing. For example, a Windows <code>ReadFile()</code> or POSIX <code>aio_read()</code> API returns immediately and initiates an internal system read operation. Of the three approaches, this non-blocking asynchronous approach offers the best scalability and performance. </p>
<p>This article investigates different non-blocking I/O multiplexing mechanisms and proposes a single multi-platform design pattern/solution. We hope that this article will help developers of high performance TCP based servers to choose optimal design solution. We also compare the performance of Java, C# and C++ implementations of proposed and existing solutions. We will exclude the blocking approach from further discussion and comparison at all, as it the least effective approach for scalability and performance. </p>
<h1>Reactor and Proactor: two I/O multiplexing approaches</h1>
<p>In general, I/O multiplexing mechanisms rely on an event demultiplexor [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>1</font></u></a>, <a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>3</font></u></a>], an object that dispatches I/O events from a limited number of sources to the appropriate read/write event handlers. The developer registers interest in specific events and provides event handlers, or callbacks. The event demultiplexor delivers the requested events to the event handlers. </p>
<p>Two patterns that involve event demultiplexors are called Reactor and Proactor [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>1</font></u></a>]. The Reactor patterns involve synchronous I/O, whereas the Proactor pattern involves asynchronous I/O. In Reactor, the event demultiplexor waits for events that indicate when a file descriptor or socket is ready for a read or write operation. The demultiplexor passes this event to the appropriate handler, which is responsible for performing the actual read or write. </p>
<p>In the Proactor pattern, by contrast, the handler—or the event demultiplexor on behalf of the handler—initiates asynchronous read and write operations. The I/O operation itself is performed by the operating system (OS). The parameters passed to the OS include the addresses of user-defined data buffers from which the OS gets data to write, or to which the OS puts data read. The event demultiplexor waits for events that indicate the completion of the I/O operation, and forwards those events to the appropriate handlers. For example, on Windows a handler could initiate async I/O (overlapped in Microsoft terminology) operations, and the event demultiplexor could wait for IOCompletion events [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>1</font></u></a>]. The implementation of this classic asynchronous pattern is based on an asynchronous OS-level API, and we will call this implementation the "system-level" or "true" async, because the application fully relies on the OS to execute actual I/O. </p>
<p>An example will help you understand the difference between Reactor and Proactor. We will focus on the read operation here, as the write implementation is similar. Here's a read in Reactor: </p>
<ul>
    <li>An event handler declares interest in I/O events that indicate readiness for read on a particular socket
    <li>The event demultiplexor waits for events
    <li>An event comes in and wakes-up the demultiplexor, and the demultiplexor calls the appropriate handler
    <li>The event handler performs the actual read operation, handles the data read, declares renewed interest in I/O events, and returns control to the dispatcher </li>
</ul>
<p>By comparison, here is a read operation in Proactor (true async): </p>
<ul>
    <li>A handler initiates an asynchronous read operation (note: the OS must support asynchronous I/O). In this case, the handler does not care about I/O readiness events, but is instead registers interest in receiving completion events.
    <li>The event demultiplexor waits until the operation is completed
    <li>While the event demultiplexor waits, the OS executes the read operation in a parallel kernel thread, puts data into a user-defined buffer, and notifies the event demultiplexor that the read is complete
    <li>The event demultiplexor calls the appropriate handler;
    <li>The event handler handles the data from user defined buffer, starts a new asynchronous operation, and returns control to the event demultiplexor. </li>
</ul>
<h1>Current practice </h1>
<p>The open-source C++ development framework ACE [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>1</font></u></a>, <a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>3</font></u></a>] developed by Douglas Schmidt, et al., offers a wide range of platform-independent, low-level concurrency support classes (threading, mutexes, etc). On the top level it provides two separate groups of classes: implementations of the ACE Reactor and ACE Proactor. Although both of them are based on platform-independent primitives, these tools offer different interfaces. </p>
<p>The ACE Proactor gives much better performance and robustness on MS-Windows, as Windows provides a very efficient async API, based on operating-system-level support [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>4</font></u></a>, <a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>5</font></u></a>]. </p>
<p>Unfortunately, not all operating systems provide full robust async OS-level support. For instance, many Unix systems do not. Therefore, ACE Reactor is a preferable solution in UNIX (currently UNIX does not have robust async facilities for sockets). As a result, to achieve the best performance on each system, developers of networked applications need to maintain two separate code-bases: an ACE Proactor based solution on Windows and an ACE Reactor based solution for Unix-based systems. </p>
<p>As we mentioned, the true async Proactor pattern requires operating-system-level support. Due to the differing nature of event handler and operating-system interaction, it is difficult to create common, unified external interfaces for both Reactor and Proactor patterns. That, in turn, makes it hard to create a fully portable development framework and encapsulate the interface and OS- related differences. </p>
<h1>Proposed solution</h1>
<p>In this section, we will propose a solution to the challenge of designing a portable framework for the Proactor and Reactor I/O patterns. To demonstrate this solution, we will transform a Reactor demultiplexor I/O solution to an emulated async I/O by moving read/write operations from event handlers inside the demultiplexor (this is "emulated async" approach). The following example illustrates that conversion for a read operation: </p>
<blockquote>
<ul>
    <li>An event handler declares interest in I/O events (readiness for read) and provides the demultiplexor with information such as the address of a data buffer, or the number of bytes to read.
    <li>Dispatcher waits for events (for example, on <code>select()</code>);
    <li>When an event arrives, it awakes up the dispatcher. The dispatcher performs a non- blocking read operation (it has all necessary information to perform this operation) and on completion calls the appropriate handler.
    <li>The event handler handles data from the user-defined buffer, declares new interest, along with information about where to put the data buffer and the number bytes to read in I/O events. The event handler then returns control to the dispatcher. </li>
</ul>
</blockquote>
<p>As we can see, by adding functionality to the demultiplexor I/O pattern, we were able to convert the Reactor pattern to a Proactor pattern. In terms of the amount of work performed, this approach is exactly the same as the Reactor pattern. We simply shifted responsibilities between different actors. There is no performance degradation because the amount of work performed is still the same. The work was simply performed by different actors. The following lists of steps demonstrate that each approach performs an equal amount of work: </p>
<p>Standard/classic Reactor: </p>
<ul>
    <li>Step 1) wait for event (Reactor job)
    <li>Step 2) dispatch "Ready-to-Read" event to user handler ( Reactor job)
    <li>Step 3) read data (user handler job)
    <li>Step 4) process data ( user handler job) </li>
</ul>
<p>Proposed emulated Proactor: </p>
<ul>
    <li>Step 1) wait for event (Proactor job)
    <li>Step 2) read data (now Proactor job)
    <li>Step 3) dispatch "Read-Completed" event to user handler (Proactor job)
    <li>Step 4) process data (user handler job) </li>
</ul>
<p>With an operating system that does not provide an async I/O API, this approach allows us to hide the reactive nature of available socket APIs and to expose a fully proactive async interface. This allows us to create a fully portable platform-independent solution with a common external interface. </p>
<h1>TProactor</h1>
<p>The proposed solution (TProactor) was developed and implemented at Terabit P/L [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>6</font></u></a>]. The solution has two alternative implementations, one in C++ and one in Java. The C++ version was built using ACE cross-platform low-level primitives and has a common unified async proactive interface on all platforms. </p>
<p>The main TProactor components are the Engine and WaitStrategy interfaces. Engine manages the async operations lifecycle. WaitStrategy manages concurrency strategies. WaitStrategy depends on Engine and the two always work in pairs. Interfaces between Engine and WaitStrategy are strongly defined. </p>
<p>Engines and waiting strategies are implemented as pluggable class-drivers (for the full list of all implemented Engines and corresponding WaitStrategies, see Appendix 1). TProactor is a highly configurable solution. It internally implements three engines (POSIX AIO, SUN AIO and Emulated AIO) and hides six different waiting strategies, based on an asynchronous kernel API (for POSIX- this is not efficient right now due to internal POSIX AIO API problems) and synchronous Unix <code>select()</code>, <code>poll()</code>, /dev/poll (Solaris 5.8+), <code>port_get</code> (Solaris 5.10), RealTime (RT) signals (Linux 2.4+), epoll (Linux 2.6), k-queue (FreeBSD) APIs. TProactor conforms to the standard ACE Proactor implementation interface. That makes it possible to develop a single cross-platform solution (POSIX/MS-WINDOWS) with a common (ACE Proactor) interface. </p>
<p>With a set of mutually interchangeable "lego-style" Engines and WaitStrategies, a developer can choose the appropriate internal mechanism (engine and waiting strategy) at run time by setting appropriate configuration parameters. These settings may be specified according to specific requirements, such as the number of connections, scalability, and the targeted OS. If the operating system supports async API, a developer may use the true async approach, otherwise the user can opt for an emulated async solutions built on different sync waiting strategies. All of those strategies are hidden behind an emulated async fa&#231;ade. </p>
<p>For an HTTP server running on Sun Solaris, for example, the /dev/poll or <code>port_get()</code>-based engines is the most suitable choice, able to serve huge number of connections, but for another UNIX solution with a limited number of connections but high throughput requirements, a <code>select()</code>-based engine may be a better approach. Such flexibility cannot be achieved with a standard ACE Reactor/Proactor, due to inherent algorithmic problems of different wait strategies (see Appendix 2). </p>
<p>In terms of performance, our tests show that emulating from reactive to proactive does not impose any overhead—it can be faster, but not slower. According to our test results, the TProactor gives on average of up to 10-35 % better performance (measured in terms of both throughput and response times) than the reactive model in the standard ACE Reactor implementation on various UNIX/Linux platforms. On Windows it gives the same performance as standard ACE Proactor. </p>
<h1>Performance comparison (JAVA versus C++ versus C#).</h1>
<p>In addition to C++, as we also implemented TProactor in Java. As for JDK version 1.4, Java provides only the sync-based approach that is logically similar to C <code>select()</code> [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>7</font></u></a>, <a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>8</font></u></a>]. Java TProactor is based on Java's non-blocking facilities (java.nio packages) logically similar to C++ TProactor with waiting strategy based on <code>select()</code>. </p>
<p>Figures 1 and 2 chart the transfer rate in bits/sec versus the number of connections. These charts represent comparison results for a simple echo-server built on standard ACE Reactor, using RedHat Linux 9.0, TProactor C++ and Java (IBM 1.4JVM) on Microsoft's Windows and RedHat Linux9.0, and a C# echo-server running on the Windows operating system. Performance of native AIO APIs is represented by "Async"-marked curves; by emulated AIO (TProactor)—AsyncE curves; and by TP_Reactor—Synch curves. All implementations were bombarded by the same client application—a continuous stream of arbitrary fixed sized messages via N connections. </p>
<p>The full set of tests was performed on the same hardware. Tests on different machines proved that relative results are consistent. </p>
<div class=figure><img src="http://www.artima.com/articles/images/io_dp_fig_1.gif"> </div>
<div class=figurecaption>Figure 1. Windows XP/P4 2.6GHz HyperThreading/512 MB RAM. </div>
<div class=figure><img src="http://www.artima.com/articles/images/io_dp_fig_2.gif"> </div>
<div class=figurecaption>Figure 2. Linux RedHat 2.4.20-smp/P4 2.6GHz HyperThreading/512 MB RAM. </div>
<h1>User code example</h1>
<p>The following is the skeleton of a simple TProactor-based Java echo-server. In a nutshell, the developer only has to implement the two interfaces: <code>OpRead</code> with buffer where TProactor puts its read results, and <code>OpWrite</code> with a buffer from which TProactor takes data. The developer will also need to implement protocol-specific logic via providing callbacks <code>onReadCompleted()</code> and <code>onWriteCompleted()</code> in the <code>AsynchHandler</code> interface implementation. Those callbacks will be asynchronously called by TProactor on completion of read/write operations and executed on a thread pool space provided by TProactor (the developer doesn't need to write his own pool). </p>
<pre class=indent>class EchoServerProtocol implements AsynchHandler
{
AsynchChannel achannel = null;
EchoServerProtocol( Demultiplexor m,  SelectableChannel channel ) throws Exception
{
this.achannel = new AsynchChannel( m, this, channel );
}
public void start() throws Exception
{
// called after construction
System.out.println( Thread.currentThread().getName() + ": EchoServer protocol started" );
achannel.read( buffer);
}
public void onReadCompleted( OpRead opRead ) throws Exception
{
if ( opRead.getError() != null )
{
// handle error, do clean-up if needed
System.out.println( "EchoServer::readCompleted: " + opRead.getError().toString());
achannel.close();
return;
}
if ( opRead.getBytesCompleted () &lt;= 0)
{
System.out.println( "EchoServer::readCompleted: Peer closed " + opRead.getBytesCompleted();
achannel.close();
return;
}
ByteBuffer buffer = opRead.getBuffer();
achannel.write(buffer);
}
public void onWriteCompleted(OpWrite opWrite) throws Exception
{
// logically similar to onReadCompleted
...
}
}
</pre>
<p><code>IOHandler</code> is a TProactor base class. <code>AsynchHandler</code> and Multiplexor, among other things, internally execute the wait strategy chosen by the developer. </p>
<h1>Conclusion</h1>
<p>TProactor provides a common, flexible, and configurable solution for multi-platform high- performance communications development. All of the problems and complexities mentioned in Appendix 2, are hidden from the developer. </p>
<p>It is clear from the charts that C++ is still the preferable approach for high performance communication solutions, but Java on Linux comes quite close. However, the overall Java performance was weakened by poor results on Windows. One reason for that may be that the Java 1.4 nio package is based on <code>select()</code>-style API. � It is true, Java NIO package is kind of Reactor pattern based on <code>select()</code>-style API (see [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>7</font></u></a>, <a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>8</font></u></a>]). Java NIO allows to write your own <code>select()</code>-style provider (equivalent of TProactor waiting strategies). Looking at Java NIO implementation for Windows (to do this enough to examine import symbols in jdk1.5.0\jre\bin\nio.dll), we can make a conclusion that Java NIO 1.4.2 and 1.5.0 for Windows is based on WSAEventSelect () API. That is better than <code>select()</code>, but slower than IOCompletionPort�s for significant number of connections. . Should the 1.5 version of Java's nio be based on IOCompletionPorts, then that should improve performance. If Java NIO would use IOCompletionPorts, than conversion of Proactor pattern to Reactor pattern should be made inside nio.dll. Although such conversion is more complicated than Reactor- &gt;Proactor conversion, but it can be implemented in frames of Java NIO interfaces. (this the topic of next arcticle, but we can provide algorithm). At this time, no TProactor performance tests were done on JDK 1.5. </p>
<p>Note. All tests for Java are performed on "raw" buffers (java.nio.ByteBuffer) without data processing. </p>
<p>Taking into account the latest activities to develop robust AIO on Linux [<a href="http://www.artima.com/articles/io_design_patterns3.html#resources"><u><font color=#800080>9</font></u></a>], we can conclude that Linux Kernel API (io_xxxx set of system calls) should be more scalable in comparison with POSIX standard, but still not portable. In this case, TProactor with new Engine/Wait Strategy pair, based on native LINUX AIO can be easily implemented to overcome portability issues and to cover Linux native AIO with standard ACE Proactor interface. </p>
<h1>Appendix I</h1>
<p>Engines and waiting strategies implemented in TProactor </p>
<p>
<center>
<table border=1>
    <tbody>
        <tr bgColor=#ccccff>
            <th>Engine Type</th>
            <th>Wait Strategies</th>
            <th>Operating System</th>
        </tr>
        <tr>
            <tr vAlign=top>
                <td>POSIX_AIO (true async)<br><code>aio_read()</code>/<code>aio_write()</code></td>
                <td><code>aio_suspend()<br>Waiting for RT signal<br>Callback function</code></td>
                <td>POSIX complained UNIX (not robust)<br>POSIX (not robust)<br>SGI IRIX, LINUX (not robust)</td>
            </tr>
            <tr vAlign=top>
                <td>SUN_AIO (true async)<br><code>aio_read()</code>/<code>aio_write()</code> </td>
                <td><code>aio_wait()</code></td>
                <td>SUN (not robust)</td>
            </tr>
            <tr vAlign=top>
                <td>Emulated Async<br>Non-blocking <code>read()</code>/<code>write()</code></td>
                <td><code>select()</code><br><code>poll()</code><br>/dev/poll<br>Linux RT signals<br>Kqueue </td>
                <td>generic POSIX<br>Mostly all POSIX implementations<br>SUN<br>Linux<br>FreeBSD<br></td>
            </tr>
        </tbody>
    </table>
    </center>
    <h1>Appendix II</h1>
    <p>All sync waiting strategies can be divided into two groups: </p>
    <ul>
        <li>edge-triggered (e.g. Linux RT signals)—signal readiness only when socket became ready (changes state);
        <li>level-triggered (e.g. <code>select()</code>, <code>poll()</code>, /dev/poll)—readiness at any time. </li>
    </ul>
    <p>Let us describe some common logical problems for those groups: </p>
    <ul>
        <li>edge-triggered group: after executing I/O operation, the demultiplexing loop can lose the state of socket readiness. Example: the "read" handler did not read whole chunk of data, so the socket remains still ready for read. But the demultiplexor loop will not receive next notification.
        <li>level-triggered group: when demultiplexor loop detects readiness, it starts the write/read user defined handler. But before the start, it should remove socket descriptior from the set of monitored descriptors. Otherwise, the same event can be dispatched twice.
        <li>Obviously, solving these problems adds extra complexities to development. All these problems were resolved internally within TProactor and the developer should not worry about those details, while in the synch approach one needs to apply extra effort to resolve them. </li>
    </ul>
    <a name=resources>
    <h1>Resources</h1>
    </a>
    <p>[1] Douglas C. Schmidt, Stephen D. Huston "C++ Network Programming." 2002, Addison-Wesley ISBN 0-201-60464-7<br></p>
    <p>[2] W. Richard Stevens "UNIX Network Programming" vol. 1 and 2, 1999, Prentice Hill, ISBN 0-13- 490012-X <br></p>
    <p>[3] Douglas C. Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann "Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects, Volume 2" Wiley &amp; Sons, NY 2000<br></p>
    <p>[4] INFO: Socket Overlapped I/O Versus Blocking/Non-blocking Mode. Q181611. Microsoft Knowledge Base Articles.<br></p>
    <p>[5] Microsoft MSDN. I/O Completion Ports.<br><a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/i_o_completion_ports.asp"><u><font color=#0000ff>http://msdn.microsoft.com/library/default.asp?url=/library/en- us/fileio/fs/i_o_completion_ports.asp</font></u></a> </p>
    <p>[6] TProactor (ACE compatible Proactor).<br><a href="http://www.artima.com/articles/www.terabit.com.au"><u><font color=#0000ff>www.terabit.com.au</font></u></a> </p>
    <p>[7] JavaDoc java.nio.channels<br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/nio/channels/package-summary.html"><u><font color=#0000ff>http://java.sun.com/j2se/1.4.2/docs/api/java/nio/channels/package-summary.html</font></u></a> </p>
    <p>[8] JavaDoc Java.nio.channels.spi Class SelectorProvider <br><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/nio/channels/spi/SelectorProvider.html"><u><font color=#0000ff>http://java.sun.com/j2se/1.4.2/docs/api/java/nio/channels/spi/SelectorProvider.html</font></u></a> </p>
    <p>[9] Linux AIO development <br><a href="http://lse.sourceforge.net/io/aio.html"><u><font color=#0000ff>http://lse.sourceforge.net/io/aio.html</font></u></a>, and<br><a href="http://archive.linuxsymposium.org/ols2003/Proceedings/All-Reprints/Reprint-Pulavarty-OLS2003.pdf"><u><font color=#0000ff>http://archive.linuxsymposium.org/ols2003/Proceedings/All-Reprints/Reprint-Pulavarty-OLS2003.pdf</font></u></a> </p>
    <p>See Also:
    <p>Ian Barile "I/O Multiplexing &amp; Scalable Socket Servers", 2004 February, DDJ <br></p>
    <p>Further reading on event handling<br><a href="http://www.cs.wustl.edu/~schmidt/ACE-papers.html"><u><font color=#0000ff>- http://www.cs.wustl.edu/~schmidt/ACE-papers.html</font></u></a> </p>
    <p>The Adaptive Communication Environment<br><a href="http://www.cs.wustl.edu/~schmidt/ACE.html"><u><font color=#800080>http://www.cs.wustl.edu/~schmidt/ACE.html</font></u></a> </p>
    <p>Terabit Solutions<br><a href="http://terabit.com.au/solutions.php"><u><font color=#0000ff>http://terabit.com.au/solutions.php</font></u></a> </p>
    <h1>About the authors</h1>
    <p>Alex Libman has been programming for 15 years. During the past 5 years his main area of interest is pattern-oriented multiplatform networked programming using C++ and Java. He is big fan and contributor of ACE.
    <p>Vlad Gilbourd works as a computer consultant, but wishes to spend more time listening jazz :) As a hobby, he started and runs <a href="http://www.corporatenews.com.au/"><u><font color=#0000ff>www.corporatenews.com.au</font></u></a> website. </p>
<img src ="http://www.cppblog.com/wy/aggbug/40947.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/wy/" target="_blank">鱼儿</a> 2008-01-11 10:39 <a href="http://www.cppblog.com/wy/articles/40947.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>