MSDN在ReadFile()
函数的描述中声明:
如果使用
FILE_FLAG_OVERLAPPED
打开hFile,则lpOverlapped参数必须指向有效且唯一的OVERLAPPED
结构,否则该函数可能会错误地报告读取操作已完成。
我有一些违反上述建议的应用程序,我想知道问题的严重性。我的意思是该程序使用已使用FILE_FLAG_OVERLAPPED
创建的命名管道,但它使用以下调用从中读取:
ReadFile(handle, &buf, n, &n_read, NULL);
这意味着它将NULL
作为lpOverlapped
参数传递。根据文档,在某些情况下,该调用不应该正常工作。我花了很多时间试图重现这个问题,但我无法做到!我总是在正确的时间将所有数据放在正确的位置。我虽然只测试了命名管道。
有人知道我什么时候可以预期ReadFile()会错误地返回并报告成功完成,即使数据还没有在缓冲区中?为了重现这个问题会发生什么?是否会出现文件,管道,套接字,控制台或其他设备?我是否必须使用特定版本的操作系统?或者特定版本的读取(比如将句柄注册到I / O完成端口)?或者是读写进程/线程的特定同步?
或者什么时候会失败?它对我有用:/
请帮忙!
关于,马丁
答案 0 :(得分:3)
在系统内部,系统仅支持异步I / O.对于同步I / O,系统使用OVERLAPPED
创建临时hEvent = NULL;
结构,发出传递此临时的异步I / O请求,然后使用GetOverlappedResult( bWait = TRUE )等待完成。
回想一下,临时hEvent
结构的OVERLAPPED
为NULL
并注意GetOverlappedResult的备注部分:
如果OVERLAPPED结构的hEvent成员为NULL,则系统使用hFile句柄的状态来指示操作何时完成。
文件HANDLE
是一个可等待的对象,在I / O操作开始时变为无信号,并在I / O操作结束时发出信号。
现在考虑一种情况,即在发出同步I / O请求时异步文件HANDLE
具有挂起的I / O请求。系统创建OVERLAPPED
结构并等待hFile HANDLE
完成。与此同时,异步I / O完成,从而发出HANDLE
信号,导致同步I / O过早返回,而没有实际完成。
更糟糕的是,当响应同步I / O请求而启动的异步I / O完成时,它将更新不再存在的临时OVERLAPPED
结构。结果是内存损坏。
完整的故事可以在The Old New Thing找到。
答案 1 :(得分:0)
似乎您处于违反记录的最佳做法而故意调用API的情况。在这种情况下,所有赌注都是关闭的。它可能有效,但可能没有。如果可以在此OS上运行,但不能在OS的下一次迭代或同一OS的下一个Service Pack上运行。当你移植到Win64时会发生什么?它还能继续吗?
调用GetLastError()(或在调试器中查看@ ERR,hr)是否提供除错误代码之外有用的任何值?
我建议您使用有效的OVERLAPPED结构调用它,使其工作并消除所有疑问(以及随机失败的可能性)。当您可以通过使用有效的OVERLAPPED结构轻松解决问题时,为什么软件中可能存在错误的代码(并且很难重现错误)?
答案 2 :(得分:0)
为什么要问问题而不是修改代码来按原样调用API?
我怀疑它似乎总是有效,因为即使这是一个异步I / O,它也会很快完成。根据您测试成功的方式,该功能可能会错误地报告操作已完成,但在测试结果之前它实际上已完成。
真正的测试是在读取数据之前对管道进行读取。
但实际上,你应该修改代码。如果您的体系结构无法处理异步I / O,则从创建命名管道中删除FILE_FLAG_OVERLAPPED
。
答案 3 :(得分:0)
当他们说
时块引用 如果使用FILE_FLAG_OVERLAPPED打开hFile,则lpOverlapped参数必须指向有效且唯一的OVERLAPPED结构,否则该函数可能会错误地报告读取操作已完成。
他们的意思是代码中没有任何东西阻止它工作,但是他们的代码中还有一条路径会产生错误的结果。仅仅因为你不能用你的特定硬件重现问题并不意味着没有问题。
如果你真的想重现这个问题,请保持原样,继续你的生活。关于你忘记这个问题的所有时间,奇怪的行为将表明与调用ReadFile没有任何明显的关系。你会花几天时间把头发拉出来,这个问题似乎会随机出现。最终你会找到它并因为没有遵循指示而踢自己。在那里,做到了,没有乐趣!
重新创建问题的另一种方法是为您的客户安排重要的演示。那肯定会失败!
如果您不想使用OVERLAPPED结构和所有相关的返回值检查(Waits,Events等)来破坏您的代码,您可以编写一个包装函数,该函数包含一个可以读取的句柄和一个超时。只需用这个方便的包装器替换你对ReadFile的调用。