异步过程解读

为什么要采用异步读写的方式:

磁盘的访问速度远远的低于内存的速度,所以OS要等待磁盘设备读写结果
如果采用同步,那么任务将会被挂起,等待磁盘读好数据,通知OS,然后唤醒
高性能的服务器,为了提高并发,读写文件都会采用异步的模式

异步读写的过程:

-w300

这样App层并不会被挂起,可以接着处理其他的业务

项目约束

  • 目录层级结构

src 存放项目代码
bin 存放待读取的文件

  • 修改工作目录

-w400
选择bin文件夹

Windows 同步读取实现

  • 同步打开一个文件
HANDLE WINAPI CreateFile(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile );

这里需要注意的是,如果当前你的编译环境定义了UNICODE的宏,你需要在lpFileName前面加上L,代表此段字符串为Unicode编码

  • 同步读取一个文件
BOOL WINAPI ReadFile(hFile, buf, max_len,&dwRead,&overlap); 
  • 关闭文件
BOOL WINAPI CloseHandle(HANDLE hObject);
  • 代码实现
    HANDLE hfile = INVALID_HANDLE_VALUE;
    hfile = CreateFile("in.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

#pragma region 同步读取

    if (hfile == INVALID_HANDLE_VALUE) {

        printf("open error.\n");
        goto failed;
    }

    char buf[1024];
    int readed;

    ReadFile(hfile, buf, 1024, &readed, NULL);
    buf[readed] = 0; // 文件结束标志位
    printf("%s\n", buf);

    CloseHandle(hfile);
#pragma endregion
  • 执行结果

Windows 异步读取

  • 异步打开一个文件
HANDLE hFile = CreateFile(路径, GENERIC_READ, 0,NULL,OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL,NULL);

这里于同步不同的地方是,dwFlagsAndAttributes使用的是FILE_FLAG_OVERLAPPED|FILE_ATTRIBUTE_NORMAL

-w300

  • 创建一个OVERLAPPED对象,传递给OS,并携带一个事件,当读取完成后,触发此事件
    OVERLAPPED overlap;
    overlap.Offset = 0;
    overlap.hEvent = hEvent;
  • 读文件
BOOL WINAPI ReadFile(hFile, buf, max_len,&dwRead,&overlap);    
  • 将事件加入等待集合来等待完成
DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)

如果这里需要等待多个需要使用WaitForMultipleObjectsAPI

  • 关闭一个文件
BOOL WINAPI CloseHandle(HANDLE hObject);
  • 代码实现
# pragma region 异步读取

    hfile = CreateFile("in.txt", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_ATTRIBUTE_NORMAL, NULL);

    if (hfile == INVALID_HANDLE_VALUE) {

        printf("open error.\n");
        goto failed;
    }

    OVERLAPPED ov;
    HANDLE hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
    memset(&ov, 0, sizeof(ov));

    ov.hEvent = hevent;
    ov.Offset = 0;
    ReadFile(hfile, buf, 1024, &readed, &ov);

    if (GetLastError() == ERROR_IO_PENDING) {

        WaitForSingleObject(hevent, INFINITE);
        readed = ov.InternalHigh;
        buf[readed];
        printf("%s\n", buf);
        CloseHandle(hfile);
    } else {

        CloseHandle(hfile);
}

#pragma endregion
  • 执行结果


What doesn’t kill you makes you stronger.