Overlapped I/O模型深入分析
简述:
Overlapped I/O也称 Asynchronous I/O,异步I/O模型。异步I/O和同步I/O不同,同步I/O时,程序被挂起,一直到I/O处理完,程序才能获得控制。异步I/O,调用一个函数告诉OS,进行I/O操作,不等I/O结束就立即返回,继续程序执行,操作系统完成I/O之后,通知消息给你。Overlapped I/O只是一种模型,它可以由内核对象(hand),事件内核对象(hEvent), 异步过程调用(apcs) 和完成端口(I/O completion)实现。
Overlapped I/O的设计的目的:
取代多线程功能,(多线程存在同步机制,错误处理,在成千上万个线程 I/O中,线程上下文切换是十分消耗CPU资源的)。
Overlapped I/O模型是 OS为你传递数据,完成上下文切换,在处理完之后通知你。由程序中的处理,变为OS的处理。内部也是用线程处理的。
Overlapped数据结构:
typedef struct _OVERLAPPED {
DWORD Internal; 通常被保留,当 GetOverlappedResult()传回False并且GatLastError()并非传回ERROR_IO_PENDINO时,该状态置为系统定的状态。
DWORD InternalHigh; 通常被保留,当 GetOverlappedResult()传回False时,为
被传输数据的长度。
DWORD Offset;
指定文件的位置,从该位置传送数据,文件位置是相对文件开始
处的字节偏移量。调用 ReadFile或WriteFile函数之前调用进
程设置这个成员,读写命名管道及通信设备时调用进程忽略这
个成员;
DWORD OffsetHigh;
指定开始传送数据的字节偏移量的高位字,读写命名管道及通
信设备时调用进程忽略这个成员;
HANDLE hEvent;
标识事件,数据传送完成时把它设为信号状态,调用ReadFile
WriteFile ConnectNamedPipe TransactNamedPipe
函数
前,调用进程设置这个成员. 相关函数
CreateEvent ResetEvent GetOverlappedResult
WaitForSingleObject CWinThread GetLastError
} OVERLAPPED, *LPOVERLAPPED;
二个重要功能:
1. 标识每个正在 overlapped 的操作。
2. 程序和系统之间提供了共享区域。参数可以在区域内双向传递。
OVERLAPPED和数据缓冲区释放问题 :
在请求时,不能释放,只有在 I/O请求完成之后,才可以释放。如果发出多个overlapped请求,每个overlapped读写操作,都必须包含文件位置(socket),另外,如果有多个磁盘,I/O执行次序无法保证。(每个overlapped都是独立的请求操作)。
内核对象(hand)实现:
例子:用 overlapped模型读一个磁盘文件内容。
1.把设备句柄看作同步对象, ReadFile将设备句柄设为无信号。ReadFile 异步I/O字节位置必须在OVERLAPPED结构中指定。
2.完成 I/O,设置信息状态。为有信号。
3. WaitForSingleObject或WaitForMultipleObject判断
或者异步设备调用 GetOverLappedResult函数。
int main()
{
BOOL rc;
HANDLE hFile;
DWORD numread;
OVERLAPPED overlap;
char buf[READ_SIZE];
char szPath[MAX_PATH];
CheckOsVersion();
GetWindowsDirectory(szPath, sizeof(szPath));
strcat(szPath, "//WINHLP32.EXE");
hFile = CreateFile( szPath,
GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open %s/n", szPath);
return -1;
}
memset(&overlap, 0, sizeof(overlap));
overlap.Offset = 1500;
rc = ReadFile(
hFile,
buf,
READ_SIZE,
&numread,
&overlap
);
printf("Issued read request/n");
if (rc)
{
printf("Request was returned immediately/n");
}
else
{
if (GetLastError() == ERROR_IO_PENDING)
{
printf("Request queued, waiting.../n");
WaitForSingleObject(hFile, INFINITE);
printf("Request completed./n");
rc = GetOverlappedResult(
hFile,
&overlap,
&numread,
FALSE
);
printf("Result was %d/n", rc);
}
else
{
printf("Error reading file/n");
}
}
Clo