[转]重叠IO
本章回答了如下几个问题:
◆ 什么是Overlapped I/O?为什么需要Overlapped I/O?如何让数据传输支持Overlapped I/O?
◆ 数据传输结束后,Win32提供了哪些方式对用户进行通告,以便进行适当的善后?
◆ 影响线程优先级的因素有哪些?如何获取或设置进程线程优先级?优先级的改变容易带来哪些问题?又该如何应对?
◆ 什么是被激发的文件句柄?什么是被激发的事件?什么是异步进程调用(APCs)?这些方式各是如何实现Overlapped I/O的?各有何优缺点?
◆ 使用Overlapped I/O的初衷是使“受制于I/O的程序”中获得高效率。但是否是各种情况下Overlapped I/O都能提高系统效率吗?
◆ 什么是I/O completion port?这个机制是怎么工作的?有什么优点?为什么说此方式能够很好地支持scalable(可升级的)系统?而对于工作于此模式下的文件,从提高系统效率考虑,怎样才能避免无谓的completion packet通告呢?
什么是Overlapped I/O?
Overlapped I/O,常被设计为多线程处理,以便在一个“受制于I/O的程序”中获得高效率。
利用Win32所谓的overlapped I/O特性,可以让I/O操作并行处理,并且当一个I/O完成时,程序会收到一个通告。有些系统把这个特性称为非阻塞I/O,或异步I/O。
overlapped I/O是Win32的一项技术,你可以要求操作系统为你传送数据,并且传送完毕后通知你。这项技术使你的程序在I/O进行中仍然能够继续处理事务。事实上,操作系统内部正是以线程来完成overlapped I/O。这样,你可以获得线程的所有利益,而不需付出痛苦代价。
在Windows 95环境下,Overlapped I/O使用有些限制。它不支持磁盘或光盘中的文件操作。
Win32文件操作函数
HANDLE CreateFile(
LPCTSTR lpFileName, // pointer to name of the file
DWORD dwDesiredAccess, // access (read-write) mode
DWORD dwShareMode, // share mode
LPSECURITY_ATTRIBUTES lpSecurityAttributes,// pointer to security attributes
DWORD dwCreationDisposition, // how to create
DWORD dwFlagsAndAttributes, // file attributes
HANDLE hTemplateFile // handle to file with attributes to copy
);
BOOL ReadFile(
HANDLE hFile, // handle of file to read
LPVOID lpBuffer, // pointer to buffer that receives data
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read
LPOVERLAPPED lpOverlapped // pointer to structure for data
);
BOOL WriteFile(
HANDLE hFile, // handle to file to write to
LPCVOID lpBuffer, // pointer to data to write to file
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED lpOverlapped // pointer to structure for overlapped I/O
);
BOOL CloseHandle(
HANDLE hObject // handle to object to close
);
一些说明:
CreateFile()可处理的对象包括:files、pipes、mailslots、communication resource、disk device(Windows NT only)、consoles、directories(open only)。
如果要使用异步I/O,CreateFile()时设置dwFlagsAndAttributes含FILE_FLAG_OVERLAPPED标志,通知操作系统对此文件的访问采取异步I/O模式。
由于异步I/O模式下,可以在同一时间读(或写)文件的许多部分,所以没有“目前的文件位置”这一概念。每次读写都必须包含其文件位置。
OVERLAPPED结构
typedef struct _OVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
说明:
Internal
通常它被保留。然而,当GetOverlappedResult()返回FALSE,GetLastError()返回ERROR_IO_PENDING时,这个栏位将内含一个视系统而定的状态。
InternalHigh
通常它被保留。然而,当GetOverlappedResult()返回TRUE时,这个栏位将内含“被传输的数据长度”。
Offset
定义文件开始读(或写)的开始位置,以字节为单位。该偏离位置从文件头开始起算。如果目标设备不支持文件位置(比如管道),此栏忽略。
OffsetHigh
64位的文件偏离量,较高的32位。如果目标设备不支持文件位置(比如管道),此栏忽略。
hEvent
一个手动事件。当overlapped I/O完成后即被激发。ReadFileEx()和WriteFileEx()忽略这个栏位,彼时它可能用来传输一个用户自定义的指针。
注意: OVERLAPPED结构的生命周期应超越ReadFile()和WriteFile()函数。
被激发的File Handles
注意,此方式在Windows95/98下不被支持。详看MSDN中关于GetOverlappedResult()函数的说明。
在Windows NT下,最简单的overlapped I/O类型,是使用它自己的文件句柄作为同步机制。大致流程如下:
- 调用CreateFile(),设置dwFlagsAndAttributes含FILE_FLAG_OVERLAPPED标志,通知操作系统对此文件的访问采取异步I/O模式;
- 建立一个OVERLAPPED结构,其中包含I/O请求所需参数;
- 调用ReadFile()或WriteFile(),最后一个参数为OVERLAPPED结构为参数。此时Win32会在后台处理你的请求;
- 使用wait…()函数,并将该文件的文件句柄作为参数,等待操作结束。文件句柄是核心对象,一旦操作完成即被激发;
- 使用GetOverlappedResult()函数,查询操作结果。此时你获得的结果和调用ReadFile()、WriteFile()而没指定overlapped I/O所传回的东西一样。
- 文件使用完毕,CloseHandle()。
BOOL GetOverlappedResult(
HANDLE hFile, // handle to file, pipe, or comm device
LPOVERLAPPED lpOverlapped, // pointer to overlapped structure
LPDWORD lpNumberOfBytesTransferred, // pointer to actual bytes count
BOOL bWait // wait flag
);
说明:如果bWait设置为FALSE,如果overlapped I/O还没完成,函数返回FALSE,调用GetLastError()会返回ERROR_IO_INCOMPLETE。所以,调用GetOverlappedResult()时如果bWait设置为FALSE,可即时查询overlapped I/O的状态。
举例:
hFile = CreateFile( szPath,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return -1;
}
// Initialize the OVERLAPPED structure
memset(&overlap, 0, sizeof(overlap));
overlap.Offset = 1500;
// Request the data
rc = ReadFile( hFile,buf,READ_SIZE,&numread,&overlap);
if (rc)
{
// The data was read successfully
}
else
{
if (GetLastError() == ERROR_IO_PENDING)
{
VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(hFile, INFINITE));
rc = GetOverlappedResult(hFile, &overlap,&numread,FALSE);
}
else
{
// Something went wrong
}
}
CloseHandle(hFile);
说明:
- 来源:(http://blog.sina.com.cn/s/blog_5678943c0100d6fc.html) - 第六章 Overlapped I/O,在你身后变戏法(1)_流水_新浪博客
虽然你要求一个overlapped操作,但如果数据已被放入cache中,或操作系统认为它可以快速地取得那份你所要求的数据,那么文件操作会在ReadFile()返回前完成。此时ReadFile()返回TRUE。
- 如果你要求一个文件操作为overlapped操作,而操作系统把这个“操作请求”放到队列中等待执行,那么ReadFile()或WriteFile()都会传回FALSE以示失败。但函数返回FALSE有多种原因,可调用GetLastError()调查原因,如果是ERROR_IO_PENDING,那说明“操作请求”被放入队列等待执行;其它值,那可能真正代表一个错误了。
- OVERLAPPED结构中包含了“这个操作从哪里开始的信息”,可以处理64位的偏移量。
- WaitForSingleObject(hFile, INFINITE); rc = GetOverlappedResult(hFile, &overlap,&numread,FALSE);其实可合并为一句:rc = GetOverlappedResult(hFile, &overlap,&numread,TRUE);
被激发的事件对象
使用文件句柄作为激发机制,有一个明显的限制:如果多个线程对同一个文件进行操作,由于只有一个相同的handle,对于每个可能进行的overlapped操作都调用GetOverlappedResult()查看操作是否完成,这将不是一个很有效率的做法——因为很多的时候并不是自己所期待的操作完成了。另外,Windows95/98下不可以使用文件句柄作为激发机制。
OVERLAPPED结构中的最后一个栏位是一个事件句柄。如果使用文件句柄作为激发对象,可将该位设置为NULL。如果该位被设定为一个事件对象时,系统核心会在overlapped操作完成后,自动设置此事件为激发。
由于每个overlapped操作都有它独一无二的OVERLAPPED结构,每个结构都有它独一无二的事件对象,用以代表该操作。
注意:OVERLAPPED结构中的事件必须是手动事件。否则,如果事件为自动事件,由于系统核心可能会在你有机会等待该事件前就激发它,而自动事件的激发状态是不能保留的,于是事件遗失,这将导致你的等待永远无法返回。
使用手动事件配搭overlapped I/O,就可以对同一个文件发出多个读取操作和多个写入操作,每个操作都有自己的事件对象。然后调用wait…()函数等待其中之一或全部完成。
异步过程调用(Asynchronous Procedure Calls,APCs)
使用overlapped I/O配搭手动事件,会产生两个问题:
- 使用WaitForMultipleObjects()最多只能等待MAXIMUM_WAIT_OBJECTS个对象。对于Win32,此值目前为64。如果等待的对象超过64,就会出问题。
- 必须不断地根据“哪一个事件被激发”而计算如何反应。
异步过程调用可解决此问题。此时只要使用“Ex”版的ReadFile()和WriteFile()。这两函数可额外指定一个参数,定义一个callback函数。当一个overlapped I/O完成时,系统调用该callback函数。这个callback函数被称为I/O completion routine,因为,系统是在一个特定的overlapped I/O完成后调用它的。
但是,需要注意的是,一个特定的overlapped I/O完成后,Windows并不会贸然中断你的程序,然后调用你所提供的callback函数。那显然可能会带来新的问题。只有线程说“好,现在是一个安全时机”时系统才会调用你的callback函数。以Windows的说法,只有线程处于所谓的“alertabe”状态,回调函数才会被执行,否则对I/O completion routine的调用会被暂时搁置下来。因此,当一个线程终于处于“alertabe”状态时,可能有一堆储备的APCs等待被处理。
如果线程因为以下5个函数而处于等待状态,而其“alertabe”标志被设置为TRUE,则该现程就是处于“alertabe”状态:
DWORD SleepEx(
DWORD dwMilliseconds, // time-out interval in milliseconds
BOOL bAlertable // early completion flag
);
DWORD WaitForSingleObjectEx(
HANDLE hHandle, // handle to object to wait for
DWORD dwMilliseconds, // time-out interval, in milliseconds
BOOL bAlertable // return to execute I/O completion routine if TRUE
);
DWORD WaitForMultipleObjectsEx(
DWORD nCount, // number of handles in handle array
CONST HANDLE *lpHandles, // points to the object-handle array
BOOL fWaitAll, // wait flag
DWORD dwMilliseconds, // time-out interval in milliseconds
BOOL bAlertable // alertable wait flag
)
DWORD MsgWaitForMultipleObjectsEx(
DWORD nCount, // number of handles in handle array
LPHANDLE pHandles, // pointer to an object-handle array
DWORD dwMilliseconds, // time-out interval in milliseconds
DWORD dwWakeMask, // type of input events to wait for
DWORD dwFlags // wait flags
);
DWORD SignalObjectAndWait(
HANDLE hObjectToSignal, // handle to object to signal
HANDLE hObjectToWaitOn, // handle to object to wait for
DWORD dwMilliseconds, // time-out interval in milliseconds
BOOL bAlertable // alertable flag
);
只有使用上面这些函数进行等待ReadFileEx()或WriteFileEx()操作,回调函数才会被执行。
回调函数解释
VOID CALLBACK FileIOCompletionRoutine(
DWORD dwErrorCode, // completion code
DWORD dwNumberOfBytesTransfered, // number of bytes transferred
LPOVERLAPPED lpOverlapped // pointer to structure with I/O information
);
dwErrorCode:0表示操作完成,ERROR_HANDLE_EOF表示操作到文件尾
dwNumberOfBytesTransfered:真正被传输的数据字节数
lpOverlapped:指向OVERLAPPED结构,由开启overlapped I/O操作的函数提供。由于APCs时OVERLAPPED结构中hEvent栏位不需要用来放置一个事件句柄,此栏程序员可自由运用,比如用作回调函数的入口参数。
对文件进行Overlapped I/O的缺点
在Windows NT测试时发现,Windows NT似乎是以“I/O请求”的大小来决定是否进行overlapped I/O。如果数据量较小,系统实际上总是采取非overlapped方式进行文件读取;数据量略大些,采取Overlapped I/O其实比单纯调用ReadFile()并无优越性,相反地,效率降低。如果文件数据量比较大,Overlapped I/O才能凸显其优越性。
[转]重叠IO的更多相关文章
- Socket重叠IO
1.为什么到现在才弄懂这个 不知道这个Socket重叠IO这种模型是不是socket IO完成端口的基础,不过我感觉,学习一下这个再去学习socket IO完成端口是比较有好处的. 这个Scoket重 ...
- winSocket编程(九)重叠IO
重叠模型的优点 重叠模型的基本原理 关于重叠模型的基础知识 重叠模型的实现步骤 多客户端情况的注意事项 一.重叠模型的优点 1.可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口 ...
- 重叠IO
一. 异步IO 说到重叠模型首先还是提一下异步IO比较好,因为从本质上讲,重叠模型也是一种异步IO模型. 我们知道,相对于计算机执行的其他操作而言,设备IO(文件.管道.套接 ...
- 重叠io操作
第一章 一. 重叠模型的优点 1. 可以运行在支持Winsock2的所有Windows平台 ,而不像完成端口只是支持NT系统. 2. 比起阻塞.select.WSAAsyncSelect以及WSAEv ...
- WinSock 重叠IO模型
title: WinSock 重叠IO模型 tags: [WinSock 模型, 网络编程, 重叠IO模型] date: 2018-06-29 20:26:13 categories: Windows ...
- windows网络模型之重叠IO的使用
大部分内容转载自https://blog.csdn.net/piggyxp/article/details/114883 目录: 1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基 ...
- 四.Windows I/O模型之重叠IO(overlapped)模型
1.适用于除Windows CE之外的各种Windows平台.在使用这个模型之前应该确保该系统安装了Winsock2.重叠模型的基本设计原理是使用一个重叠的数据结构,一次投递一个或多个Winsock ...
- 重叠IO 模型
1. 重叠模型的优点 2. 重叠模型的基本原理 3. 关于重叠模型的基础知识 4. 重叠模型的实现步骤 5. 多客户端情况的注意事项 一.重叠模型的优点 1.可以运行在支持Winsock2的所有W ...
- 重叠IO overlapped I/O 运用详解
2009年02月21日 星期六 下午 07:54 I/O设备处理必然让主程序停下来干等I/O的完成,对这个问题有 方法一:使用另一个线程进行I/O.这个方案可行,但是麻烦. ...
- windows网络模型之重叠IO(完成例程)的使用
#include <WINSOCK2.H> #include <stdio.h> #define PORT 5150 #define MSGSIZE 1024 #pragma ...
随机推荐
- 安卓Activity界面切换添加动画特效
在Android 2.0之后有了overridePendingTransition() ,其中里面两个参数,一个是前一个activity的退出两一个activity的进入, @Override pub ...
- mysql 5.7.12 新增 X plugin 详解
https://dev.mysql.com/doc/refman/5.7/en/document-store.html 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息 ...
- php中序列化与反序列化在utf8和gbk编码中测试
在php中如果我们统一编码是没有什么问题了,但是很多朋友会发现一个问题就是utf8和gbk编码中返回的值会有所区别: php 在utf8和gbk编码下使用serialize和unserialize互相 ...
- 电商平台如何接入快递鸟电子面单API?
快递鸟是全球物流接口服务商,为电商 ERP.电商平台.仓储.清关公司提供物流跟踪.电子面单.智选物流.物流金融.在线下单等服务,解决电商的物流管理模块和金融模块.现就对快递鸟电子面单API做基本描述, ...
- Android 高级UI设计笔记02:可以拖动交换item位置的GridView(转载)
如果大家不知道GridView基本使用,可以先参见:Android(java)学习笔记154:使用GridView以及重写BaseAdapter 1. 首先我们明白GridView拖拽的思路: ()根 ...
- Debian 7 安装 Docker
Debian 7更新内核到3.16后 一.添加docker源 在source.list中加入: # Docker Repo deb https://get.docker.io/ubuntu docke ...
- memcached linux / win32 1.4.13
memcached-win32-1.4.13 点击下载 http://pan.baidu.com/s/1kTMABaf memcached -d install (安装为windows service ...
- xmpp搭建服务器
二.环境配置1.安装mysql2.修改mysql的帐户的密码>sqlite(移动平台) ,是没有密码直接连接数据库>mysql sqlServer (服务端的数据库) 是有帐户和密码 默 ...
- 【AR】增强现实安卓编程 - Vuforia SDK 的安装和使用 (Android Studio)
Vuforia是个强大的AR平台.使用Vuforia API 可以实现物体识别,图片追踪,柱型追踪,多对象追踪,自定义目标追踪,云识别,文字识别,帧标识和虚拟按钮等功能. 它支持Android, iO ...
- [改善Java代码]多线程使用Vector或HashTable
Vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本,这些概念我 们都很清楚,也被前辈嘱咐过很多次,但我们经常会逃避使用Vector和HashTable,因为用 ...