没有合适的资源?快使用搜索试试~ 我知道了~
Windows系统编程之异步I/O和完成端口,从操作系统的角度讲述完成端口的原理。
资源推荐
资源详情
资源评论
Windows 系统编程之异步 I/O 和完成端口
【作者】北极星 2003
【来源】看雪技术论坛(bbs.pediy.com)
【时间】2006 年 7 月 1 日
一、同步 I/O 和异步 I/O
在介绍这部分内容之前先来认识下“异步 I/O”。
说起异步 IO,很容易联想到同步 I/O,对于同一个 I/O 对象句柄在同一时刻只允许一个 I/O 操作,其原
理如下图所示:
显然,当内核真正处理 I/O 的时间段(T2~T4),用户线程是处于等待状态的,如果这个时间段比较段
的话,没有什么影响;倘若这个时间段很长的话,线程就会长时间处于挂起状态。事实上,该线程完全可
以利用这段时间用处理其他事务。
异步 I/O 恰好可以解决同步 I/O 中的问题,而且支持对同一个 I/O 对象的并行处理,其原理如下图所示:
异步 I/O 在 I/O 请求完成时,可以使用让 I/O 对象或者事件对象受信来通知用户线程,而用户线程中可以
使用 GetOverlappedResult 来查看 I/O 的执行情况。
由于异步 I/O 在进行 I/O 请求后会立即返回,这样就会产生一个问题:“程序是如何取得 I/O 处理的结果
的?”。
有多种方法可以实现异步 I/O,其不同资料上的分类一般都不尽相同,但原理上都类似,这里我把实现
异步 I/O 的方法分为 3 类,本文就针对这 3 类方法进行详细的讨论。
(1)重叠 I/O
(2)异步过程调用(APC),扩展 I/O
(3)使用完成端口(IOCP)
二、使用重叠 I/O 实现异步 I/O
同一个线程可以对多个 I/O 对象进行 I/O 操作,不同的线程也可以对同一个 I/O 对象进行操作,在我的理
解中,重叠的命名就是这么来的。
在使用重叠 I/O 时,线程需要创建 OVERLAPPED 结构以供 I/O 处理。该结构中最重要的成员是
hEvent,它是作为一个同步对象而存在,如果 hEvent 为 NULL,那么此时的同步对象即为文件句柄、
管道句柄等 I/O 操作对象。当 I/O 完成后,会使这里的同步对象受信,从而通知用户线程。
由于在进行 I/O 请求后会立即返回,但有时用户线程需要知道 I/O 当前的执行情况,此时就可以使用
GetOverlappedResult。如果该函数的 bWait 参数为 true,那么改函数就会阻塞线程直到目标 I/O 处理
完成为止;如果 bWait 为 false,那么就会立即返回,如果此时的 I/O 尚未完,调用 GetLastError 就会
返回 ERROR_IO_INCOMPLETE。
代码示例一:
代码:
DWORDnReadByte;
BYTEbBuf[BUF_SIZE];
OVERLAPPEDov={0,0,0,0,NULL};//hEvent=NULL;
HANDLEhFile=CreateFile(……,FILE_FLAG_OVERLAPPED,……);
ReadFile(hFile,bBuf,sizeof(bBuf),&nReadByte,&ov);
//由于此时 hEvent=NULL,所以同步对象为 hFile,下面两句的效果一样
WaitForSingleObject(hFile,INFINITE);
//GetOverlappedResult(hFile,&ov,&nRead,TRUE);
这段代码在调用 ReadFile 后会立即返回,但在随后的 WaitForSingleObject 或者
GetOverlappedResult 中阻塞,利用同步对象 hFile 进行同步。
这段代码在这里可以实现正常的异步 I/O,但存在一个问题,倘若现在需要对 hFile 句柄进行多个 I/O 操
作,就会出现问题。见下面这段代码。
代码示例二:
代码:
DWORDnReadByte;
BYTEbBuf1[BUF_SIZE],bBuf2[BUF_SIZE],bBuf3[BUF_SIZE];
OVERLAPPEDov1={0,0,0,0,NULL};
OVERLAPPEDov2={0,0,0,0,NULL};
OVERLAPPEDov3={0,0,0,0,NULL};
HANDLEhFile=CreateFile(……,FILE_FLAG_OVERLAPPED,……);
ReadFile(hFile,bBuf1,sizeof(bBuf1),&nReadByte,&ov1);
ReadFile(hFile,bBuf2,sizeof(bBuf2),&nReadByte,&ov2);
ReadFile(hFile,bBuf3,sizeof(bBuf3),&nReadByte,&ov3);
//假设三个 I/O 处理的时间比较长,到这里还没有结束
GetOverlappedResult(hFile,&ov1,&nRead,TRUE);
这里对于 hFile 有三个重叠的 I/O 操作,但他们的同步对象却都为 hFile。使用 GetOverlappedResult
进行等待操作,这里看似在等待第一个 I/O 处理的完成,其实只要有任何一个 I/O 处理完成,该函数就会
返回,相当于忽略了其他两个 I/O 操作的结果。
其实,这里有一个很重要的原则:对于一个重叠句柄上有多于一个 I/O 操作的时候,应该使用事件对象
而不是文件句柄来实现同步。正确的实现见示例三。
代码示例三:
代码:
DWORDnReadByte;
BYTEbBuf1[BUF_SIZE],bBuf2[BUF_SIZE],bBuf3[BUF_SIZE];
HANDLEhEvent1=CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLEhEvent2=CreateEvent(NULL,FALSE,FALSE,NULL);
HANDLEhEvent3=CreateEvent(NULL,FALSE,FALSE,NULL);
OVERLAPPEDov1={0,0,0,0,hEvent1};
OVERLAPPEDov2={0,0,0,0,hEvent2};
OVERLAPPEDov3={0,0,0,0,hEvent3};
HANDLEhFile=CreateFile(……,FILE_FLAG_OVERLAPPED,……);
剩余10页未读,继续阅读
资源评论
whw0828
- 粉丝: 12
- 资源: 4
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功