Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 创建一个异步;ReadFileMany();在ReadFile()之上_C_Winapi_Visual C++_Readfile - Fatal编程技术网

C 创建一个异步;ReadFileMany();在ReadFile()之上

C 创建一个异步;ReadFileMany();在ReadFile()之上,c,winapi,visual-c++,readfile,C,Winapi,Visual C++,Readfile,我正在尝试创建一个函数,ReadFileMany,它模拟了ReadFile的接口,该接口提供了一个要读取的(偏移量、长度)对列表,并异步读取文件的所有部分 我在ReadFileMany中这样做,使用RegisterWaitForSingleObject来指示线程池线程等待I/O完成,以便它可以再次调用ReadFile来读取文件的下一部分,等等 我遇到的问题是,我似乎无法模仿ReadFile的特定行为 具体而言,文件句柄本身可以像事件一样使用,而不需要事件句柄: OVERLAPPED ov = {

我正在尝试创建一个函数,
ReadFileMany
,它模拟了
ReadFile
的接口,该接口提供了一个要读取的(偏移量、长度)对列表,并异步读取文件的所有部分

我在
ReadFileMany
中这样做,使用
RegisterWaitForSingleObject
来指示线程池线程等待I/O完成,以便它可以再次调用
ReadFile
来读取文件的下一部分,等等

我遇到的问题是,我似乎无法模仿
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
一样运行,或者不可能正确地执行它?

假设您试图读取单个文件的多个部分,我只需分配一个重叠的
结构数组,对于文件的每个请求部分,一次启动所有
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;
尝试
{
std::向量ri(numSections);
std::载体h;
h、 储备(numSections);
对于(int i=0;iov.Offset=ul.LowPart;
r->ov.OFFETHIGH=ul.HighPart;
r->pBuffer=…;//需要读入的缓冲区
r->dwNumBytes=…;//需要读取的字节数
如果(!ReadFile(hFile,r->pBuffer,r->dwNumBytes,&r->dwNumBytes读取,&r->ov))
{
如果(GetLastError()!=错误\u IO\u挂起)
抛出std::exception();
r->bPending=true;
h、 向后推(r->ov.hEvent);
}
}
如果(!h.empty())
{
if(WaitForMultipleObjects(h.size(),&h[0],TRUE,无穷大)!=WAIT\u OBJECT\u 0)
抛出std::exception();
}
对于(int i=0;iB结束)
GetOverlappedResult(hFile,&r->ov,&r->DWnumbytes读取,FALSE);
// ...
}
}
捕获(const std::exception&)
{
取消(hFile);
返回false;
}
返回true;

您从哪里想到可以将文件句柄传递给
WaitForSingleObject()
?文件句柄不是可等待的对象,所以你不能等待它。这就是你要写的吗?@Damon:不;事实上,恰恰相反。
ReadFileScatter
中的“分散”指的是内存缓冲区(内存中分散的页面),而
ReadFileMemory
中的“多”指的是文件的不同部分。@RemyLebeau:是的,实际上可以。(试试看。)显然,
ReadFile
文档似乎没有提到它,但是如果你看一下,你会发现这是完全正确的,文件句柄可以像事件句柄一样发出信号:“通过等待文件句柄,调用线程可以同步到读取操作的完成。每次在句柄上发出的I/O操作完成时,都会向句柄发出信号。“@Mehrdad:根据该文档,仅当文件以
SYNCHRONIZE
访问权限打开时,并且仅当一次只执行一个I/O操作时,它才起作用。应使用
ZwWaitForSingleObject()完成等待
CreateFile()
ReadFile()
WaitFor…()
文档都没有提到任何关于文件句柄作为可等待对象被支持的内容,所以我真的不会依赖于这种行为。
ZwReadFile()
是比
ReadFile()更低级别的API
,所以不要将较低级别和较高级别的API语义混合在一起。有趣的是……这不会在磁盘上造成很大的震动吗?用户如何知道所有读取都已完成,而不是仅完成其中一个读取?似乎我们仍然存在与以前相同的问题。它仍然是重叠的I/O,因此Windows可以安排实际的读取视情况而定的光盘活动。如果仔细观察,我将设置
WaitForMultipleObjects()的
bWaitAll
参数
设置为TRUE,因此在所有请求的读取完成之前它不会退出。看起来您完全错过了问题,这与等待文件句柄有关。您正在等待事件句柄,这已经是我在问题中提到的,但它没有为问题提供与我之前提到的相同的接口仔细阅读问题,了解问题的实质。
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;