标签:Windows;异步;IO;
当我们对文件进行读写时,线程本该是梗阻的,即线程在期待读写操纵的结束,这种方法称为
同步I/O。Windows在系统层为我们供给了一种高效的机制——
异步IO。
异步IO供给了这样一种成果:当你读取文件时,读取函数会立刻返回,读取任务转交给系统底层自动措置惩罚惩罚,,这样文件的读取操纵就不会梗阻线程。IO操纵完成时,由系统发出完成通知。
介绍三种完成通知:
1.直接期待句柄(文件期待东西)
2.期待OVERLAPPED中的hEvent句柄(期待事件东西)
3.异步挪用(APC挪用)
主要函数:CreateFile();ReadFile();WriteFile();
数据成员:OVERLAPPED布局体。
一个句柄如果是以异步IO的方法打开,那这个句柄就具有了两个特性:
1.文件变为可期待的东西(即具有激发态和非激发态)
2.文件指针掉效(需要通过OVERLAPPED布局体中的的Offect暗示读取或写入的位置,而不能用SetFilePointer()这样的函数。)
代码实例:(VS2015控制台)
筹备:Debug目录下创建123.exe并生存数据
1.直接期待句柄
#include "stdafx.h"
#include <windows.h>
typedef struct _MYOVERLAPPED{
OVERLAPPED ol;
HANDLE hFile;
PBYTE pBuf;
int nIndex;
}MYOVERLAPPED,*PMYOVERLAPPED;
DWORD WINAPI ThreadProc(LPVOID lParam) {
PMYOVERLAPPED pol = (PMYOVERLAPPED)lParam;
WaitForSingleObject(pol->hFile, INFINITE);
for (int i=0;i<10;i++)
{
printf("%d:%d \n", pol->nIndex,pol->pBuf[i]);
}
printf("读完了!\n");
return 0;
}
int main()
{
// 1. 异步IO符号
// 有了这个符号 该文件就变为可期待的内查东西
// 后面的read write函数就变为非梗阻的
HANDLE hFile = CreateFile(L"123.txt", GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL| FILE_FLAG_OVERLAPPED, NULL);
// 2. 文件读取
PMYOVERLAPPED pol = new MYOVERLAPPED{};
pol->ol.Offset = 0x0;// 从偏移0x100这个位置开始读
// pol->hEvent == NULL; 系统读取完成后,会把我的hFile变为有信号状态
pol->hFile = hFile;
pol->pBuf = new BYTE[0x1000]{};
pol->nIndex =1;
ReadFile(hFile,
pol->pBuf,
0x1000,
NULL,//实际读取的个数,由OVERLAPPED布局体指定
(LPOVERLAPPED)pol);
HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, pol, NULL, NULL);
PMYOVERLAPPED pol2 = new MYOVERLAPPED{};
pol2->ol.Offset = 0x0;// 从偏移0x100这个位置开始读
// pol->hEvent == NULL; 系统读取完成后,会把我的hFile变为有信号状态
pol2->hFile = hFile;
pol2->pBuf = new BYTE[0x1000]{};
pol2->nIndex = 2;
ReadFile(hFile,
pol2->pBuf,
0x1000,
NULL,//实际读取的个数,由OVERLAPPED布局体指定
(LPOVERLAPPED)pol2);
HANDLE hThread2 = CreateThread(NULL, NULL, ThreadProc, pol2, NULL, NULL);
// ......干其他事
WaitForSingleObject(hThread, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
return 0;
}
2.期待事件东西
#include "stdafx.h"
#include <windows.h>
typedef struct _MYOVERLAPPED {
OVERLAPPED ol;
HANDLE hFile;
PBYTE pBuf;
int nIndex;
}MYOVERLAPPED, *PMYOVERLAPPED;
DWORD WINAPI ThreadProc(LPVOID lParam) {
PMYOVERLAPPED pol = (PMYOVERLAPPED)lParam;
printf("开始期待......\n");
WaitForSingleObject(pol->ol.hEvent, INFINITE);
for (int i = 0; i < 10; i++)
{
printf("%d:%02x \n", pol->nIndex, pol->pBuf[i]);
}
printf("读完了!\n");
return 0;
}
int main()
{
// 1. 异步IO符号
// 有了这个符号 该文件就变为可期待的内查东西
// 后面的read write函数就变为非梗阻的
HANDLE hFile = CreateFile(L"..\\Debug\\123.exe", GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// 2. 文件读取
PMYOVERLAPPED pol = new MYOVERLAPPED{};
pol->ol.Offset = 0x100;// 从偏移0x100这个位置开始读
pol->ol.hEvent = CreateEvent(NULL,NULL,FALSE,NULL); //系统读取完成后,会把我的hFile变为有信号状态
pol->hFile = hFile;// 被无视
pol->pBuf = new BYTE[0x1000]{};
pol->nIndex = 1;
ReadFile(hFile,
pol->pBuf,
0x1000,
NULL,//实际读取的个数,由OVERLAPPED布局体指定
(LPOVERLAPPED)pol);
HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, pol, NULL, NULL);
PMYOVERLAPPED pol2 = new MYOVERLAPPED{};
pol2->ol.Offset = 0x200;// 从偏移0x100这个位置开始读
pol2->ol.hEvent = CreateEvent(NULL, NULL, FALSE, NULL); //系统读取完成后,会把我的hFile变为有信号状态
pol2->hFile = hFile;// 被无视
pol2->pBuf = new BYTE[0x1000]{};
pol2->nIndex = 2;
ReadFile(hFile,
pol2->pBuf,
0x1000,
NULL,//实际读取的个数,由OVERLAPPED布局体指定
(LPOVERLAPPED)pol2);
HANDLE hThread2 = CreateThread(NULL, NULL, ThreadProc, pol2, NULL, NULL);
// ......干其他事
WaitForSingleObject(hThread, INFINITE);
WaitForSingleObject(hThread2, INFINITE);
return 0;
}
3.异步挪用(APC挪用)
异步挪用供给了这样一个机制:你可以在读取文件或者写入文件的时候,供给一个回调函数,当读写任务完成时,就会挪用这个回调函数。
#include "stdafx.h"
#include <windows.h>
typedef struct _MYOVERLAPPED {
OVERLAPPED ol;
HANDLE hFile;
PBYTE pBuf;
int nIndex;
}MYOVERLAPPED, *PMYOVERLAPPED;
// 提交任务的线程措置惩罚惩罚,其他线程看着
VOID CALLBACK FileIOCompletionRoutine(
_In_ DWORD
dwErrorCode,
_In_ DWORD
dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped
) {
PMYOVERLAPPED pol = (PMYOVERLAPPED)lpOverlapped;
for (int i = 0; i < 10; i++)
{
printf("%d:%02x \n", pol->nIndex, pol->pBuf[i]);
}
printf("读完了!\n");
}
int main()
{
// 1. 异步IO符号
// 有了这个符号 该文件就变为可期待的内查东西
// 后面的read write函数就变为非梗阻的
HANDLE hFile = CreateFile(L"..\\Debug\\123.exe", GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// 2. 文件读取
PMYOVERLAPPED pol = new MYOVERLAPPED{};
pol->ol.Offset = 0x100;// 从偏移0x100这个位置开始读
// hEvent被无视 hFile也被无视
//pol->ol.hEvent = CreateEvent(NULL, NULL, FALSE, NULL); //系统读取完成后,会把我的hFile变为有信号状态
pol->hFile = hFile;// 被无视
pol->pBuf = new BYTE[0x1000]{};
pol->nIndex = 1;
ReadFileEx(hFile,
pol->pBuf,
0x1000,
(LPOVERLAPPED)pol,
FileIOCompletionRoutine);// 完成后直接挪用该回调函数,不用期待文件句柄/事件东西
PMYOVERLAPPED pol2 = new MYOVERLAPPED{};
pol2->ol.Offset = 0x200;// 从偏移0x100这个位置开始读
//pol2->ol.hEvent = CreateEvent(NULL, NULL, FALSE, NULL); //系统读取完成后,会把我的hFile变为有信号状态
//pol2->hFile = hFile;// 被无视
pol2->pBuf = new BYTE[0x1000]{};
pol2->nIndex = 2;
ReadFileEx(hFile,
pol2->pBuf,
0x1000,
(LPOVERLAPPED)pol2,
FileIOCompletionRoutine);
// FileIOCompletionRoutine有系统挪用
// 哪个线程执行该函数呢
// 哪个线程read/write 哪个线程执行
// ......干其他事
// 忙完了 想起来还有两个函数等着我呢
// CPU检测到当前线程的APC行列队伍里有函数需要执行
// 就去执行该函数,执行完返回
// 只有当第2个参数是TRUE才去执行
SleepEx(200, TRUE);
// WaitForSingleObjectEx()
return 0;
}
Windows异步I/O详解
标签:Windows;异步;IO;