2

MSDN 在其ReadFile()功能描述中指出:

如果 hFile 使用 打开FILE_FLAG_OVERLAPPED,lpOverlapped 参数必须指向一个有效且唯一的OVERLAPPED结构,否则该函数可能会错误地报告读取操作已完成。

我有一些应用程序违反了上述建议,我想知道问题的严重性。我的意思是该程序使用已创建的命名管道FILE_FLAG_OVERLAPPED,但它使用以下调用从中读取:

ReadFile(handle, &buf, n, &n_read, NULL);

这意味着它NULL作为lpOverlapped参数传递。根据文档,该调用在某些情况下不应正常工作。我花了很多时间试图重现这个问题,但我无法做到!我总是在正确的时间将所有数据放在正确的位置。我只测试了命名管道。

有人知道我什么时候可以期望 ReadFile() 会错误地返回并报告成功完成,即使数据尚未在缓冲区中?为了重现问题,必须发生什么?文件、管道、套接字、控制台或其他设备是否会发生这种情况?我必须使用特定版本的操作系统吗?还是特定版本的读取(例如注册 I/O 完成端口的句柄)?或者读写进程/线程的特定同步?

或者什么时候会失败?这个对我有用 :/

请帮忙!

关于,马丁

4

4 回答 4

3

系统内部只支持异步 I/O。对于同步 I/O,系统会创建一个临时OVERLAPPED结构,发出一个传入该临时结构的异步 I/O 请求,然后使用GetOverlappedResult(bWait = TRUE)hEvent = NULL;等待完成。

回想一下hEvent临时OVERLAPPED结构的 是NULL并注意GetOverlappedResult的 Remarks 部分:

如果 OVERLAPPED 结构的 hEvent 成员为 NULL,则系统使用 hFile 句柄的状态来指示操作何时完成。

文件HANDLE是一个可等待的对象,在 I/O 操作开始时变为未发出信号,在 I/O 操作结束时发出信号。

现在考虑一个场景,HANDLE在您发出同步 I/O 请求时,异步文件有一个挂起的 I/O 请求。系统创建一个OVERLAPPED结构并等待 hFileHANDLE完成。与此同时,异步 I/O 完成,从而发出信号,HANDLE导致同步 I/O 过早返回,而实际上尚未完成。

更糟糕的是,当响应同步 I/O 请求而启动的异步 I/O 完成时,它将更新OVERLAPPED不再存在的临时结构。结果是内存损坏。

完整的故事可以在The Old New Thing找到。

于 2012-12-22T15:31:30.570 回答
0

似乎您处于故意调用 API 违反记录的最佳实践的情况。在这种情况下,所有的赌注都被取消了。它可能有效,也可能无效。如果可以在此操作系统上运行,但不能在操作系统的下一个迭代或同一操作系统的下一个服务包上运行。移植到 Win64 时会发生什么?到时候还能用吗?

除了错误代码之外,调用 GetLastError() (或在调试器中查看 @ERR,hr )是否提供任何有用的值?

我建议您使用有效的 OVERLAPPED 结构调用它,让它工作并消除所有疑问(以及随机失败的可能性)。当您可以通过使用有效的 OVERLAPPED 结构轻松解决问题时,为什么您的软件中可能存在错误代码(并且很难重现错误)?

于 2010-03-18T19:47:42.637 回答
0

为什么要问这个问题而不是修复代码以按预期调用 API?

我怀疑它似乎总是可以工作,因为即使这是一个异步 I/O,它也能很快完成。根据您测试成功的方式,该函数可能错误地报告操作已完成,但它实际上在您测试结果之前完成。

真正的测试是在读取数据之前对管道进行读取。

但实际上,您应该只修复代码。如果您的体系结构无法处理异步 I/O,FILE_FLAG_OVERLAPPED则从命名管道的创建中删除。

于 2010-03-18T20:12:28.943 回答
0

当他们说

Blockquote 如果使用 FILE_FLAG_OVERLAPPED 打开 hFile,则 lpOverlapped 参数必须指向一个有效且唯一的 OVERLAPPED 结构,否则函数会错误地报告读取操作已完成。

他们的意思是代码中没有任何东西阻止它工作,但也有一条通过他们的代码的路径可能会产生错误的结果。仅仅因为您无法重现特定硬件的问题并不意味着没有问题。

如果您真的想重现此问题,请保留代码并继续您的生活。就在您完全忘记这个问题的时候,会出现与调用 ReadFile 没有任何明显关系的奇怪行为。你会花几天时间把头发拔出来,问题似乎来来去去都是随机的。最终你会发现它并因为不遵循说明而自责。去过那里,做过,没有乐趣!

重现问题的另一种方法是为您的客户安排一个重要的演示。那肯定会失败!

如果您不想使用 OVERLAPPED 结构和所有相关的返回值检查、等待、事件等来破坏您的代码,您可以编写一个包装函数,该函数接受一个读取句柄和一个超时。只需用这个方便的花花公子包装器替换您对 ReadFile 的调用。

于 2010-11-02T01:27:50.733 回答