在 ReadFile() 之上创建异步 "ReadFileMany()"

标签 c winapi visual-c++ readfile

我正在尝试创建一个函数,ReadFileMany,它模仿 ReadFile 的接口(interface),该接口(interface)给出了一个列表(偏移量) ,长度)对进行读取,并异步读取文件的所有部分。

我在 ReadFileMany 中执行此操作,方法是使用 RegisterWaitForSingleObject 指示线程池线程等待 I/O 完成,以便它可以调用 再次读取文件以读取文件的下一部分,等等

我遇到的麻烦是我似乎无法模仿 ReadFile 的某些行为。
具体来说,文件句柄本身可以像事件一样使用,而无需事件句柄:

OVERLAPPED ov = {0};
DWORD nw;
if (ReadFile(hFile, buf, buf_size, &nw, &ov))
{
    if (WaitForSingleObject(hFile, INFINITE) == WAIT_OBJECT_0)
    {
        ...
    }
}

但是,当然,如果用户等待文件句柄,他可能会收到一个通知,表明中间读取已完成,而不是最终读取。

因此,在 ReadFileMany 中,除了最后一部分之外,我别无选择,只能将 hEvent 参数传递给 ReadFile 。 。

问题是,是否有任何方法仍然允许用户在读取所有部分后等待文件句柄发出信号?

起初答案似乎很明显:在读取最后部分时避免传递事件句柄即可!
如果读取成功,则效果很好,但如果出现错误,则效果不佳。如果 ReadFile 在上次读取时突然返回错误,我将需要手动将文件句柄设置为有信号状态,以便让读者从他的状态中醒来。可能调用 WaitForSingleObject(hFile)

但是似乎没有办法在不执行实际 I/O 的情况下将文件句柄设置为有信号状态...所以这就是我陷入困境的地方:有什么方法可以让我编写这个函数,使其在外部表现得像 ReadFile 一样,还是不可能正确执行?

最佳答案

假设您正在尝试读取单个文件的多个部分,我将简单地分配一个 OVERLAPPED 结构数组,每个请求的文件部分对应一个数组,启动所有 ReadFile() 一次性调用,然后使用 WaitForMultipleObjects() 等待所有 I/O 完成,例如:

struct sReadInfo
{
    OVERLAPPED ov;
    LPVOID pBuffer;
    DWORD dwNumBytes;
    DWORD dwNumBytesRead;
    bool bPending;

    sReadInfo()
    {
        memset(&ov, 0, sizeof(OVERLAPPED));
        pBuffer = NULL;
        dwNumBytes = 0;
        dwNumBytesRead = 0;
        bPending = false;

        ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
        if (!ov.hEvent) throw std::exception();
    }

    ~sReadInfo()
    {
        CloseHandle(hEvent);
    }
};

.

bool error = false;

try
{
    std::vector<sReadInfo> ri(numSections);

    std::vector<HANDLE> h;
    h.reserve(numSections);

    for(int i = 0; i < numSections; ++i)
    {
        ULARGE_INTEGER ul;
        ul.QuadPart = ...; // desired file offset to read from

        sReadInfo *r = &ri[i];

        r->ov.Offset = ul.LowPart;
        r->ov.OffsetHigh = ul.HighPart;

        r->pBuffer = ...; // desired buffer to read into
        r->dwNumBytes = ...; // desired number of bytes to read

        if (!ReadFile(hFile, r->pBuffer, r->dwNumBytes, &r->dwNumBytesRead, &r->ov))
        {
            if (GetLastError() != ERROR_IO_PENDING)
                throw std::exception();

            r->bPending = true;
            h.push_back(r->ov.hEvent);
        }
    }

    if (!h.empty())
    {
        if (WaitForMultipleObjects(h.size(), &h[0], TRUE, INFINITE) != WAIT_OBJECT_0)
            throw std::exception();
    }

    for (int i = 0; i < numSections; ++i)
    {
        sReadInfo *r = &ri[i];

        if (r->bPending)
            GetOverlappedResult(hFile, &r->ov, &r->dwNumBytesRead, FALSE);

        // ...
    }
}
catch (const std::exception &)
{
    CancelIo(hFile);
    return false;
}

return true;

关于在 ReadFile() 之上创建异步 "ReadFileMany()",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15393921/

相关文章:

c++ - 具有绝对路径的 LoadLibrary 返回不正确的 HMODULE,没有错误

c++ - MSVC2005 std::_Iterator_base::function 在调试时速度缓慢

c - 执行任何命令行 shell,如 execve

c++ - 为什么控制台动画在 Windows 上这么慢? (有没有办法提高速度?)

c - For 循环未按预期工作

c - 使用滚动条调整窗口大小时出现奇怪的效果

c++ - Visual Studio 2008 C++ 误报内存地址位置

c++ - Windows 服务配置文件的存储位置

c# - 等价于 C# 中的 yield

c++ - win32 应用程序是否只有一个消息循环?还是每个窗口一个消息循环?