重叠I/O之使用完成例程的扩展I/O【系列二】
一 废话
在上一篇文章中,我们介绍了通过等待内核对象来接受I/O完成通知的重叠I/O。除了使用同步对象外,我们还可以使用其它方法,这便是这篇文章要介绍的使用完成例程的扩展I/O。完成例程其实就是回调函数,当I/O完成的时候系统调用一个用户指定的回调函数来通知用户I/O完成, 调用完回调函数之后,可以继续启动下一个I/O操作。为了实现回调,线程需要处于可通知的状态。为什么称之为“扩展I/O”呢?因为它是等待内核对象的异步I/O的扩展,而且它需要调用扩展函数。
二 相关数据结构和函数
1 ReadFileEx 和 WriteFileEx
为什么是ReadFileEx和WriteFileEx,而不是使用函数ReadFile和WriteFile?额。。。一是因为当I/O完成的时候需要调用用户设置的回调函数,而回调函数的地址怎么和相关I/O异步过程调用队列相关联;二是ReadFile和WriteFile发送I/O操作请求时,异步情况下会立刻返回,所以函数参数中的已传输字节数这个参数是没有用的。所以,我们需要新的函数ReadFileEx和WriteFileEx,下面是两个函数的原型:
BOOL
WINAPI
ReadFileEx(
HANDLE hFile,
(FILE) LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
); BOOL
WINAPI
WriteFileEx(
HANDLE hFile,
(nNumberOfBytesToWrite) LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPOVERLAPPED lpOverlapped,
LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
ReadFileEx和WriteFileEx的前三个参数和ReadFile和WriteFile中的一样。lpOverlapped必须提供提供OVERLAPPED结构,但是不用设置hEvent成员,系统将忽略它。但是,可以将其设置为表示I/O操作的信息,比如顺序号。lpCompletionRoutine是所要设置的I/O回调函数的地址,回调函数的原型为:
VOID
(WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(
__in DWORD dwErrorCode,
__in DWORD dwNumberOfBytesTransfered,
__inout LPOVERLAPPED lpOverlapped
);
2 可提醒的等待函数
当I/O请求完成时候,系统会将它们添加到线程的APC队列中——回调函数并不会立即被调用,这是因为线程可能还在忙于其它的事情。为了对线程APC队列中的项进行处理,线程必须将自己设置为可提醒状态。这样当线程执行到可提醒状态点时,而APC队列中刚好有已经完成的I/O操作,则会调用回到函数。Windws共提供了6个函数可将线程置为可提醒状态:
WINBASEAPI
DWORD
WINAPI
SleepEx(
__in DWORD dwMilliseconds,
__in BOOL bAlertable
); WINBASEAPI
DWORD
WINAPI
WaitForSingleObjectEx(
__in HANDLE hHandle,
__in DWORD dwMilliseconds,
__in BOOL bAlertable
); WINBASEAPI
DWORD
WINAPI
WaitForMultipleObjectsEx(
__in DWORD nCount,
__in_ecount(nCount) CONST HANDLE *lpHandles,
__in BOOL bWaitAll,
__in DWORD dwMilliseconds,
__in BOOL bAlertable
); WINBASEAPI
DWORD
WINAPI
SignalObjectAndWait(
__in HANDLE hObjectToSignal,
__in HANDLE hObjectToWaitOn,
__in DWORD dwMilliseconds,
__in BOOL bAlertable
); BOOL
WINAPI
GetQueuedCompletionStatusEx(
__in HANDLE CompletionPort,
__out_ecount_part(ulCount, *ulNumEntriesRemoved) LPOVERLAPPED_ENTRY lpCompletionPortEntries,
__in ULONG ulCount,
__out PULONG ulNumEntriesRemoved,
__in DWORD dwMilliseconds,
__in BOOL fAlertable
); DWORD
WINAPI
MsgWaitForMultipleObjectsEx(
__in DWORD nCount,
__in_ecount_opt(nCount) CONST HANDLE *pHandles,
__in DWORD dwMilliseconds,
__in DWORD dwWakeMask,
__in DWORD dwFlags);
前五个函数的最后一个参数是一个布尔值,表示调用线程是否应该将自己置为可提醒状态。最后一个函数MsgWaitForMutipleObjectsEx需要使用MWMO_ALTERABLE来让线程进入可提醒状态。返回值表示它们返回的原因,如果返回的或者通过GetLastError为WAIT_IO_COMPLETION,表示线程至少处理了APC队列中的一项。
注意:
- 对任何可提醒的等待函数使用INFINITE超时值。
- 使用重叠结构中的hEvent数据成员来将信息传递给回调函数。
3 异步过程调用队列(asynchronous procedure call, APC)
到底完成例程的I/O操作是怎么运转的呢?我们从头开始梳理。这就需要了解异步过程调用队列(asynchronous procedure call, APC),APC队列是由系统在内部维护的。当系统创建一个线程的时候,会同是创建一个与之相关联的队列,称之为异步过程调用。当我们调用ReadFileEx或WriteFileEx向设备驱动程序发出一个I/O请求后立刻返回,但是会将回调函数的地址传给设备驱动程序。当设备驱动程序完成I/O请求的时候,便会在发出I/O请求的线程的APC队列中添加一项。该项包含了完成函数的地址,以及发出此I/O请求所使用的OVERLAPPED结构的地址。
当我们调用可提醒函数将线程设置为可提醒状态时,系统会首先检查线程的APC队列。如果队列中至少有一项,系统便会将APC队列中的那一项取出,让线程调用回调函数,并在OVERLAPPED结构中传入已完成I/O请求的错误码,已传输的字节数,以及OVERLAPPED结构的地址。当回调函数返回的时候,系统会检查APC队列是否还有其它的项,如果还有则继续处理下一项。即当一个线程进入可提醒状态时,该线程的APC队列中的所有完成例程都会得到执行。注意,系统会以任意的顺序执行我们添加到队列中的I/O请求。
三 示例
重叠I/O之使用完成例程的扩展I/O【系列二】的更多相关文章
- zw版【转发·台湾nvp系列例程】halcon与delphi系列例程
zw版[转发·台湾nvp系列例程]halcon与delphi系列例程 台湾nvp技术论坛,是目前halcon与delphi例程最多的网站,也是唯一成系列的, http://zip.nvp.com.tw ...
- 重叠I/O模型
一. 重叠I/O的概念当调用ReadFile和WriteFile时,如果最后一个参数lpOverlapped设置为NULL,那么线程就阻塞在这里,直到读写完指定的数据后,它们才返回.这样在读写大文件的 ...
- 套接字I/O模型-重叠I/O
重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...
- 四.Windows I/O模型之重叠IO(overlapped)模型
1.适用于除Windows CE之外的各种Windows平台.在使用这个模型之前应该确保该系统安装了Winsock2.重叠模型的基本设计原理是使用一个重叠的数据结构,一次投递一个或多个Winsock ...
- IOCP入门
完成端口(Completion Port)详解 此文讲解最好,也很全面一下其他文章看看就行,也可不看. 单句柄数据,单IO数据 此文讲述比较清晰,可以辅助理解上文. IOCP编程之基本原理:http: ...
- 完成端口(Completion Port)详解(转)
手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解 ...
- 完成端口(CompletionPort)详解
手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解 ...
- 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三
手把手叫你玩转网络编程系列之三 完毕port(Completion Port)具体解释 ...
- 完成端口IOCP详解
修改自: http://blog.csdn.net/piggyxp/article/details/6922277 ps: 原作者很厉害了, 把一个iocp模型讲解的这么形象,不过在实践过程中发现一些 ...
随机推荐
- 转载 SharePoint【Site Definition 系列】– 创建Content Type
转载原地址: http://www.cnblogs.com/wsdj-ITtech/archive/2012/09/01/2470274.html Sharepoint本身就是一个丰富的大容器,里面 ...
- 【Away3D代码解读】(二):渲染核心流程(简介、实体对象收集)
我之前解析过Starling的核心渲染流程,相比Away3D而言Starling真的是足够简单,不过幸运的是两者的渲染流程是大体上相似的:Starling的渲染是每帧调用Starling类中的rend ...
- VB操作CAD
Dim xlapp As Excel.Application Dim xlbook As Excel.Workbook Dim sheet As Excel ...
- Oracle中的User与Schema
Oracle中有两个概念容易混淆──user和schema,本随笔记录并摘抄了一些促进理解这连个概念的理解方法,希望有助于分清这两个概念. user是控制权限的,而schema则是一个容器,非所有者如 ...
- SQLite使用教程11 表达式
SQLite 表达式 表达式是一个或多个值.运算符和计算值的SQL函数的组合. SQL 表达式与公式类似,都写在查询语言中.您还可以使用特定的数据集来查询数据库. 语法 假设 SELECT 语句的基本 ...
- cocos2d-x 获取图片的某像素点的RGBA颜色
转自:http://www.cnblogs.com/jaoye/archive/2013/02/19/2916501.html ccColor4B c = {, , , }; CCPoint pt = ...
- UART与USART的差别
UART与USART都是单片机上的串口通信,他们之间的差别例如以下: 首先从名字上看: UART:universal asynchronous receiver and transmitter通用异步 ...
- php throw new Excpetion()之后,程序还往下继续运行吗?
经过测试是不会往下执行的,直接catch抛出异常了.
- Android硬件加速
Android从3.0(API Level 11)开始,在绘制View的时候支持硬件加速,充分利用GPU的特性,使得绘制更加平滑,但是会多消耗一些内存. 开启或关闭硬件加速: 由于硬件加速自身并非完美 ...
- android Animation 动画效果介绍
Android的animation由四种类型组成 XML中 alpha 渐变透明度动画效果 scale 渐变尺寸伸缩动画效果 translate 画面转换位置移动动画效果 rotate 画面转移旋转动 ...