PoEdu培训 Windows班 第十一课 Windows异步IO操作(二)
文章类别: 培训笔记 0 评论

PoEdu培训 Windows班 第十一课 Windows异步IO操作(二)

文章类别: 培训笔记 0 评论

Windows 异步IO操作(二)

异步IO操作可以的四种提醒方式:

事件内核对象提醒

使用时间内核对象提醒, 可以分为以下几步:

// 事件内核对象的小例子
#include <Windows.h>

int main()
{
    HANDLE hFile = CreateFile(TEXT("Demo.txt"),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_ALWAYS,
        FILE_FLAG_OVERLAPPED,
        NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        // Read
        OVERLAPPED oRead = {0};
        oRead.Offset = 0;
        // 创建一个事件内核对象
        oRead.hEvent = CreateEvent(NULL,
            TRUE,
            FALSE,
            TEXT("ReadEvent")); // 这个名称比较重要 我们知道名称就可以得到这个事件内核对象
        BYTE bReadBuf[100] = {0};
        // 异步读取文件
        ReadFile(hFile, bReadBuf, sizeof(bReadBuf), NULL, &oRead);

        // Write
        OVERLAPPED oWrite = {0};
        oWrite.Offset = 0;
        // 创建一个事件内核对象
        oWrite.hEvent = CreateEvent(NULL,
            TRUE,
            FALSE,
            TEXT("WriteEvent")); // 这个名称比较重要 我们知道名称就可以得到这个事件内核对象
        BYTE bWriteBuf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        // 异步读取文件
        WriteFile(hFile, bWriteBuf, sizeof(bWriteBuf), NULL, &oWrite);

        // 还可以有其他操作

        // 模拟其他线程操作
        HANDLE hOverLapped[2] = {0};
        hOverLapped[0] = oRead.hEvent;
        hOverLapped[1] = oWrite.hEvent;

        while (TRUE)
        {
            DWORD dwCase = WaitForMultipleObjects(2, hOverLapped, FALSE, INFINITE);
            switch (dwCase - WAIT_OBJECT_0)
            {
            case 0:
                // 读完成
                break;
            case 1:
                // 写完成
                break;
            }
        }
    }
    else
    {
        // GetLastError()
    }

    return 0;
}

事件内核对象可用于程序和程序之间数据的共享和互通

可提醒IO

使用可提醒IO, 可以分为如下几步:

APC机制

我们都知道, 我们的进程是工厂, 线程是工人.
在线程中, 有APC机制.

APC机制

注意:
    MessageBox等函数会 阻塞 我们的线程, 但是此时的线程是不可提醒的.
    通过 SleepEx, WaitForSingleObjectEx, WaitForMultipleObjectEx, SingalObjectAndWait, MsgWaitForMultipleObjectsEx 可设置线程的 可提醒状态.

示例

#include <Windows.h>

VOID CALLBACK FileIOCommpletionRoutineRead(
    _In_ DWORD dwErrorCode,
    _In_ DWORD dwNumberOfBytesTransfered,
    _Inout_ LPOVERLAPPED lpOverlapped
)
{
    MessageBox(NULL, 
        TEXT("Read Over!"),
        TEXT("Read Over!"),
        MB_OK | MB_ICONINFORMATION);
}

int main()
{
    HANDLE hFile = CreateFile(TEXT("Demo.txt"),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_ALWAYS,
        FILE_FLAG_OVERLAPPED,
        NULL);
    if (hFile != INVALID_HANDLE_VALUE)
    {
        CONST UINT unLen = 255;
        // Read
        OVERLAPPED oRead = {0};
        oRead.Offset = 0;
        BYTE bReadBuf[unLen] = {0};
        // 异步读取文件 通过可提醒IO
        ReadFileEx(hFile, 
            bReadBuf, 
            unLen, 
            &oRead,
            FileIOCommpletionRoutineRead);
        // 设置线程为可提醒状态
        // SleepEx
        // Wait.... 函数
        // 很重要, 不设置就不会调用APC事件列表
        SleepEx(100, TRUE);

        // 可以干其他的事情了....

    }
    else
    {
        // GetLastError()
    }
    return 0;
}

不建议使用可提醒IO, 因为回调函数中可操作的数据太少
如果将ReadBuf做成全局, 那么会影响我们的文件结构逻辑

未完待续...

如有错误,请提出指正!谢谢.

回复