重叠I/O之可等待的重叠I/O【系列一】
一 什么是异步I/O
同步I/O和异步I/O的关键不同就是在发出I/O请求后,线程是否会阻塞。当线程发出一个设备I/O请求的时候,线程会被挂起来,直到设备完成I/O请求为止,这称之为同步I/O。而对于异步I/O,当线程提交了一个设备I/O请求后,可以继续运行,当内核完成I/O的请求后会通知线程I/O已完成。由于与计算机执行的大多数其它操作相比,设备I/O是其中最慢的,所以使用异步I/O在大多数情况下可以大幅度提升程序的新能,当然一些个别情况就不一定使用啦。
二 异步I/O的分类
在Windows下一共有四种异步I/O的技术,它们在启动I/O操作的方法以及用于操作何时完成的方法上有所不同:
- 等待的 重叠I/O。线程发出I/O请求之后继续执行,当线程需要I/O请求的结果才能继续时,则要么等待文件句柄,要么等待在重叠结构中指定的一个事件。根据等待对象的不同,分为等待文件句柄的重叠I/O和等待事件的重叠I/O。等待文件句柄的重叠I/O没有多大用,因为它需要等待和此文件句柄关联的所有操作完成,同步I/O基本差不多。一般我们用的是等待事件的重叠I/O,使用人工事件来实现等待。
- 完成例程的重叠I/O。完成例程,这个名词看上去似乎很高级,说白了就是个毁掉函数。这个方法允许我们向一个设备发出多个I/O请求,这些I/O请求中带有一个回调函数,即完成例程。当I/O请求完成时,如果线程处于可提醒状态,则系统会通知该线程调用它的异步队列中的回调函数来处理完成的I/O。
- I/O完成端口。I/O完成端口允许我们向一个设备同时发出多个I/O请求。它允许一个线程发出I/O请求而另外一个线程对结果进行处理,这个是是和完成例程不同之处。这个技术具有很好的伸缩性和灵活性,算是异步I/O中最好的一种方式。I/O完成端口里面有一套线程池的调度策略,所以免去了我们去维护多线程的烦恼。
三 相关数据结构和函数
下面我们来看看重叠I/O中的第一个方法----重叠I/O(等待)。先从了解重叠结构开始:
1 重叠结构 OVERLAPPED
“overlapped”是执行I/O请求的时间与其他线程执行其他任务的时间是重叠的,OVERLAPPED的结构如下:
typedef struct _OVERLAPPED {
ULONG_PTR Internal; //系统保留参数,初始化时不用设置,返回值时保存已处理的I/O请求的错误码
ULONG_PTR InternalHigh; //系统保留参数,初始化时不用设置,返回值时保存已传输的字节数
union {
struct {
DWORD Offset; //文件偏移量的低位
DWORD OffsetHigh; //文件偏移量的高位
}; PVOID Pointer;
}; HANDLE hEvent; //事件句柄,必须是手动事件
} OVERLAPPED, *LPOVERLAPPED;
参数说明:
Offset 和OffsetHigh
这两个成员构成一个64位的偏移量。如果当前操作的是文件设备,则表示当前文件I/O操作应该从哪里开始。当执行异步I/O时,系统会忽略与文件关联的内核文件指针,而是用OVERLAPPED中指定的起始偏移量,这样可以避免对同一个对象进行异步调用的时候出现混淆。对于非文件设备,则需要将这两个参数设置为0,否则I/O请求会失败,返回错误ERROR_INVALID_PARAMETER。
hEvent
不同的重叠I/O操作方法中,hEvent的设置不同。在可等待的重叠I/0操作中,如果等待的是操作的文件句柄,则不需要hEvent不需要设置;而如果通过OVERLAPPED结构中的hEvent来等待的,或者是I/O完成端口方法,则需要将此参数设置为一个人工事件,注意不能使自动事件。如果是I/O完成例程的方法,则hEvent一般都用来传递I/O操作的信息。
Internal
用来保存已经处理的I/O请求的错误码。当我们发出异步I/O请求后,设备驱动程序会将internal设置为STATUS_PENDING,表示没有错误,操作尚未开始。
InternalHigh
当异步I/O请求完成时,用来保存已经传输的字节数。
异步I/O的注意事项:
1 在异步I/O请求完成之前,一定不恩能够移动或是销毁在发出I/O请求时所使用的数据缓存和OVERLAPPED机构,否则会使内存遭到破坏。因为我们传给I/O设备的是这两个数据的地址,而I/O设备并不知道我们已经销毁了它们。
2 在执行异步I/O的时候,设备不必以先入先出的方式处理队列中的I/O请求。
3 以异步I/O执行的时候,文件的读写等相关的操作返回为FALSE不一定表示失败。必须调用GetLastError,如果GetLastError返回的是ERRO_IO_PENDING,表示I/O请求已经成功的加入到I/O队列中,会在晚些时候完成。
2 获取重叠I/O状态
当我们使用ReadFile或WriteFile向文件发送读写请求后,函数会立刻返回。大多数情况下,返回时I/O操作都未完成,所以返回的FALSE,自然我们也不知道传输的字节数了。所以我们需要另外一种方法来获取文件I/O完成时传输的字节数,这个函数便是GetOverlappedResult:
BOOL
WINAPI
GetOverlappedResult(
__in HANDLE hFile, //I/O文件句柄
__in LPOVERLAPPED lpOverlapped, //重叠结构
__out LPDWORD lpNumberOfBytesTransferred, //I/O完成时传输的字节数
__in BOOL bWait //Ture:一直等待,Flase:立刻返回
);
参数hFile和lpOverlapped组合在一起可以唯一的表示一个I/O操作。当bWait设置为True,则函数会一直等待此I/O操作完成才会返回,此时lpNumberOfBytesTransfferred中即是传输的字节数。如果bWait设置为False,函数会立刻返回,如果返回会False且GetLastError()为ERRO_IO_PENDING,表示I/O尚未完成,需要轮询检查I/O是否完成。
3 取消队列中的重叠I/O请求
如果想要取消一个已经加入到I/O队列但是尚未处理的I/O请求,则可以调用CancelIoEx取消。
BOOL
WINAPI
CancelIoEx(
__in HANDLE hFile,
__in_opt LPOVERLAPPED lpOverlapped
);
CancelIoEx不仅可以取消掉本线程发出的相关文件的I/O请求,还可以将调用线程外的其他线程发出的待处理的I/O请求取消掉。这个函数会将hFile设备待处理的I/O请求中所有与lpOverlapped参数相关联的请求都取消掉。但是由于每个待处理的I/O请求都有一个其特定的OVERLAPPED结构,所以如果lpOverlpaped非空,则CancelIoEx每次只能取消一个请求。而lpOverlpaped为NULL的话,会取消掉hFileI/O请求队列中的所有I/O请求。
四 例子:使用可等待的重叠I/O进行文件复制操作
这个示例程序使用事件来实现重叠I/O的等待。这个程序实现从输入文件中异步读数据,然后异步的写数据到输出文件中。程序采用多缓冲区的方法进行文件的转换,假设输入和输出各采用N个缓冲区,则N个输入缓冲和N个输出缓冲需要N个输入重叠结构和N个输出重叠结构与其对应。初始时,N个输入缓冲分别发出重叠的读操作,然后程序使用WaitForMultipleObjects来等待单一的I/O操作完成事件,表示一个读或写操作完成。当一个读操作完成时,则对缓冲区进行复制,然后发起一个写操作请求。当写完成时,就可以进行下一个读操作请求了。
重叠I/O之可等待的重叠I/O【系列一】的更多相关文章
- 重叠I/O模型
一. 重叠I/O的概念当调用ReadFile和WriteFile时,如果最后一个参数lpOverlapped设置为NULL,那么线程就阻塞在这里,直到读写完指定的数据后,它们才返回.这样在读写大文件的 ...
- 套接字I/O模型-重叠I/O
重叠模型的基本设计原理是让应用程序使用重叠的数据结构,一次投递一个或多个WinsockI/O请求.针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务.模型的总体设计以Windows重叠I/O ...
- 手把手教你玩转SOCKET模型之重叠I/O篇(上)
“身为一个初学者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人.我也希望大家能把自己的所学和他人一起分享,不要去鄙视别人索取时的贪婪,因为最应该被鄙视的是不肯付 ...
- 重叠I/O之事件通知
在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于select模型.异步选择和事件选择三种.重叠模型的基本设计原理便是让应用程序使 用一个重叠的数据 ...
- 关于Winsock编程中IO重叠的概念
我在看<Windows网络与通信程序设计>(王艳平)这本书时,对重叠IO很不理解,突然就冒出这么一个概念,没一点头绪.就目前的理解做一个整理. 第一种理解:OVERLAPPED,顾名思义为 ...
- winSocket编程(九)重叠IO
重叠模型的优点 重叠模型的基本原理 关于重叠模型的基础知识 重叠模型的实现步骤 多客户端情况的注意事项 一.重叠模型的优点 1.可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口 ...
- 转:变手把手教你玩转SOCKET模型之重叠I/O篇
手把手教你玩转SOCKET模型之重叠I/O篇 “身为一个初学者,时常能体味到初学者入门的艰辛,所以总是想抽空作点什么来尽我所能的帮助那些需要帮助的人.我也希望大家能把自己的所学和他人一起分享,不要去鄙 ...
- c++ 网络编程(十) LINUX/windows 异步通知I/O模型与重叠I/O模型 附带示例代码
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9662931.html 一.异步IO模型(asynchronous IO) (1)什么是异步I/ ...
- 重叠IO
一. 异步IO 说到重叠模型首先还是提一下异步IO比较好,因为从本质上讲,重叠模型也是一种异步IO模型. 我们知道,相对于计算机执行的其他操作而言,设备IO(文件.管道.套接 ...
随机推荐
- MongoDB 快速入门--高级
引用 --------->DBRefs DBRef的形式: { $ref : , $id : , $db : } $ref:集合名称 $id:引用的id $db:数据库名称,可选参数 { &qu ...
- iOS 推送证书
push 服务器证书 钥匙串:登入-->证书,选项里面导出证书命名为cert.p12,跟密钥命名为key.p12 需要将上面的2个.p12文件转成.pem格式: openssl pkcs12 - ...
- iOS GCD 与 NSOperationQueue
NSOperationQueue ios NSOperation vs. GCD StackOverflow: NSOperation vs. Grand Central Dispatch Blog: ...
- .Net枚举类型小结
1.枚举类型的要点: (1)类型声明语法: enum 枚举名 (2)枚举体语法: a.成员名称 = 整数值,其他成员名称,或者其他成员与整数的表达式 b.成员之间需要用逗号隔开 (3)枚举可以继承的 ...
- PHP获取解析URL方法
们要经常对url里面所带的参数进行解析,如果我们知道了url传递参数名称,例如: /index.php?name=tank&sex=1#top 我们就可以通过$_GET['name'],$_G ...
- dubbo-RPC学习(二) http protocol
dubbo中的协议默认支持很多种,从简单的开始,先解读HttpProtocol吧. dubbo中的http-RPC基于spring web支持的http invoker,web容器默认使用jetty. ...
- JDK 7u60 版本发布下载安装
JDK 7u60 版本发布了,主要改进包括: JavaFX 更新到 2.2.60 Java Mission Control(JMC)更新到 5.3 如果你在一个早期版本的Java中禁用了过期检查功能, ...
- True Zero Downtime HAProxy Reloads--转载
原文地址:http://engineeringblog.yelp.com/2015/04/true-zero-downtime-haproxy-reloads.html HAProxy: Corner ...
- 1002 GTY's birthday gift
GTY's birthday gift Time Limit ...
- Java基础知识强化之集合框架笔记75:哈希表
1. 哈希表数据结构(数组): 2. 哈希表确定元素是否相同: (1)判断的是两个元素的哈希值是否相同 如果相同,再判断两个对象内容是否相同 (2)判断哈希值相 ...