【免杀前置课——Windows编程】十四、异步IO——什么是异步IO、API定位问题、APC调用队列
创始人
2024-03-19 23:57:51
0

异步IO

  • 异步IO
    • 异步I/0注意事项:
  • 定位问题
    • 总解决方案
      • APC调用队列

异步IO

当我们读取一个文件时,一般情况下,线程是阻塞的,也就是说,当前线程在等待文件读取操作结束,这种方式叫同步IO
Windows 在系统底层为用户实现了另外一种高效的机制,叫重叠I/0,又称作异步I/0。异步I/0提供了这样一种功能,当用户读取文件的时候,读取文件函数会立马返回结果不会阻塞线程,但是实际上文件并没有读取完,而是交给了系统底层自动去处理,这样文件的读取操作就不会阻塞住你的线程。但是这种引发了一个问题,我们如何才能知道文件已经读取完毕了呢? I

异步I/0注意事项:

一旦一个句柄是以异步I/0的方式打开的,那么:
1、句柄变为可等待的对象,就是说,它具有了激发态和非激发态。
2、文件指针这个东西就失效了,需要用overlapped结构体中的offset表示读取或写入的位置。

在这里插入图片描述
在这里插入图片描述

定位问题

异步IO存在问题,如果不止通过一个句柄进行读操作还有其他操作,则GetOverlappedResult函数无法定位到是哪一个操作。

#include
#includeint main() 
{//用异步IO方式打开一个文件HANDLE hFile = CreateFileW(L"D:\\code\\VisualStudio2022\\异步Io\\异步Io\\test.txt", GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);//FILE_FLAG_OVERLAPPED异步IOCHAR buff[0X100]{ 0 };OVERLAPPED overlapped{ 0 };//读取文件内容ReadFile(hFile, buff, 0X100, NULL, &overlapped);DWORD numberOfBytes = 0;WaitForSingleObject(hFile, -1);GetOverlappedResult(hFile, &overlapped, &numberOfBytes, FALSE);printf("文件内容:%s\n", buff);printf("实际完成IO数:%d\n", numberOfBytes);CloseHandle(hFile);return 0;
}

在这里插入图片描述
解决无法精确定位是哪个API完成的问题。新问题是,到最后还是要调用WaitForSingleObject函数,如果操作过大还是会导致卡顿,无法流畅体验。

#include
#includeint main()
{HANDLE hFile = CreateFile(L"D:\\code\\VisualStudio2022\\异步Io\\异步Io\\test.txt", GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);OVERLAPPED overlapped{ 0 };OVERLAPPED overlapped1{ 0 };overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);overlapped1.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);char buff[0X100]{ 0 };char buff1[0X100]{ 0 };ReadFile(hFile, buff, 10, NULL, &overlapped);ReadFile(hFile, buff1, 20, NULL, &overlapped1);//精确地判断哪个结束WaitForSingleObject(overlapped.hEvent, -1);WaitForSingleObject(overlapped1.hEvent, -1);printf("%s\n", buff);printf("%s\n", buff1);return 0;
}

总解决方案

APC调用队列

每个线程都维护了一个APC(异步过程调用)队列,队列中的每一项都是函数,当一个线程处于可警醒(闲暇)状态时,线程会遍历自己的APC队列并调用所有的函数,直到结束,再恢复执行。
每当有一个异步IO请求完成的时候,ReadFileEx,就会像APC队列中添加相应的函数和对应的参数,添加的顺序和投递的顺序不一定相同,哪个先处理完就先投递哪个。

通过ReadFileEx函数,让每一个异步IO完成后都向APC队列中加入函数及相应参数,来判断线程顺序的同时不使用WaitForSingleObject等待激发且抢占不影响流畅性。

#include
#includevoid WINAPI overLappedCompletionProc(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{if (lpOverlapped->hEvent == (HANDLE)0X100){printf("1完成了\n");}else {printf("2完成了\n");}
}int main()
{HANDLE hFile = CreateFile(L"D:\\code\\VisualStudio2022\\异步Io\\异步Io\\test.txt", GENERIC_ALL, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);OVERLAPPED overlapped{ 0 };OVERLAPPED overlapped1{ 0 };//overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);//overlapped1.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);overlapped.hEvent = (HANDLE)0X100;overlapped1.hEvent = (HANDLE)0X200;char buff[0X100]{ 0 };char buff1[0X100]{ 0 };//当有一个异步IO请求完成后,就会向APC队列中添加相应的函数和对应的参数ReadFileEx(hFile, buff, 10, &overlapped, overLappedCompletionProc);ReadFileEx(hFile, buff1, 20, &overlapped1, overLappedCompletionProc);//当进程处于激发态时触发,通过Sleep让进程处于激发态SleepEx(0, TRUE);//ReadFile(hFile, buff, 10, NULL, &overlapped);//ReadFile(hFile, buff1, 20, NULL, &overlapped1);//精确地判断哪个结束//WaitForSingleObject(overlapped.hEvent, -1);//WaitForSingleObject(overlapped1.hEvent, -1);printf("%s\n", buff);printf("%s\n", buff1);return 0;
}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...