0

ReadFileManyのインターフェイスを模倣し、読み取り対象の (オフセット、長さ) ペアのリストReadFileが与えられ、ファイルのすべての部分を非同期的に読み取る関数を作成しようとしています。

ファイルの次の部分などを読み取るために再度呼び出すことができるように、I/O が完了するまで待機するようにスレッド プール スレッドを指示するためにReadFileMany使用することで、内部でこれを行っています。RegisterWaitForSingleObjectReadFile

私が直面している問題は、 の特定の動作を模倣できないように見えることですReadFile
具体的には、イベント ハンドルを必要とせずに、ファイルハンドル自体をイベントのように使用できます。

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

しかしもちろん、ユーザーがファイル ハンドルを待機している場合、最終的な読み取りではなく、中間読み取りが完了したという通知を受け取る可能性があります。

そのため、 の内部では、最後の部分を除くすべてのにパラメータをReadFileMany渡すしかありません。 hEventReadFile

問題は、すべての部分が読み取られたときにファイルハンドルがシグナル状態になるのをユーザーが待機できるようにする方法はありますか?

最初は答えが明白に思えます:最後の部分を読むときにイベント ハンドルを渡すのは避けてください!
読み取りが成功する場合は正常に機能しますが、エラーがある場合は機能しません。ReadFileが最後の読み取りで突然エラーを返し始めた場合は、ファイル ハンドルをシグナル状態に手動で設定して、リーダーが への潜在的な呼び出しから復帰できるようにする必要がありますWaitForSingleObject(hFile)

しかし、実際の I/O を実行せずにファイル ハンドルをシグナル状態に設定する方法はないようですReadFile。外、またはそれを正しく行うことは不可能ですか?

4

1 に答える 1

0

1 つのファイルの複数のセクションを読み取ろうとしていると仮定するとOVERLAPPED、ファイルの要求されたセクションごとに 1 つの構造体の配列を割り当て、一度にすべての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;
于 2013-03-13T19:47:48.920 に答える