// 08.异步IO-等待文件对象.cpp : 定义控制台应用程序的入口点。
//
// 每一次文件读取/写入操作,都要创建一个线程,
// 系统同时运行的线程数是有限的,线程的创建和销毁浪费了大量资源
// 没有效率
#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;
}
===========
// 08.异步IO-等待文件对象.cpp : 定义控制台应用程序的入口点。
//
#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:%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->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 = 0x200;// 从偏移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;
}
====================
// 08.异步IO-异步过程调用(APC).cpp : 定义控制台应用程序的入口点。
//
#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;
}
============================
// 08.异步过程调用-完成端口(IOCP).cpp : 定义控制台应用程序的入口点。
//
#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 =nullptr;
HANDLE hIOCP = lParam;
while (TRUE)
{
DWORD dwNum = 0;
ULONG_PTR uCompleteKey = 0;
BOOL bRet = GetQueuedCompletionStatus(
hIOCP,// 检查完成端口有没有待处理任务(有任务完成,通知完成端口处理)
&dwNum,// 实际传输的字节数
&uCompleteKey,// 哪个设备完成了异步操作
(LPOVERLAPPED*)&pol,
INFINITE);
if (bRet == FALSE && ERROR_ABANDONED_WAIT_0 == GetLastError())
{
printf("完成端口被关闭\n");
return 0;
}
if (uCompleteKey == NULL && pol == nullptr)
{
PostQueuedCompletionStatus(hIOCP, NULL, NULL, NULL);
printf("完成端口线程结束!\n");
return 0;
}
for (int i = 0; i < 10; i++)
{
printf("key:%d,%d:%02x \n", uCompleteKey,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. 创建一个完成端口
// 先获取核心数
SYSTEM_INFO si = {};
GetSystemInfo(&si);
HANDLE hIOCP = CreateIoCompletionPort(
INVALID_HANDLE_VALUE,// 创建完成端口,绑定完成端口的时候是文件句柄
NULL,// 创建完成端口的时候是NULL,绑定的时候是完成端口句柄
NULL,// 创建完成端口的时候是NULL,绑定的时候是自己设置的一个值,用来区分绑定的文件是哪个
si.dwNumberOfProcessors);// 完成端口上并行运行的最大线程数,绑定的时候是NULL
// 3.把完成端口和文件绑定,后面这个文件的所有异步操作的通知都交给完成端口
CreateIoCompletionPort(
hFile,
hIOCP,
0x12,// 和hFile绑定的值,也可以是hFile本身
NULL
);
// 4. 创建完成端口的服务线程
for (int i=0;i<si.dwNumberOfProcessors*2;i++)
{
CreateThread(NULL, NULL, ThreadProc, hIOCP, NULL, NULL);
}
// 5. 文件读取
PMYOVERLAPPED pol = new MYOVERLAPPED{};
pol->ol.Offset = 0x100;// 从偏移0x100这个位置开始读
pol->pBuf = new BYTE[0x1000]{};
pol->nIndex = 1;
ReadFile(hFile,
pol->pBuf,
0x1000,
NULL,//实际读取的个数,由OVERLAPPED结构体指定
(LPOVERLAPPED)pol);
PMYOVERLAPPED pol2 = new MYOVERLAPPED{};
pol2->ol.Offset = 0x200;// 从偏移0x100这个位置开始读
pol2->pBuf = new BYTE[0x1000]{};
pol2->nIndex = 2;
ReadFile(hFile,
pol2->pBuf,
0x1000,
NULL,//实际读取的个数,由OVERLAPPED结构体指定
(LPOVERLAPPED)pol2);
// ......干其他事
// 投递一个完成任务
PostQueuedCompletionStatus(hIOCP, NULL, NULL, NULL);
system("pause");
return 0;
}