SetFileCompletionNotificationModes似乎不能正常工作

SetFileCompletionNotificationModes seems to not work properly

本文关键字:工作 常工作 不能 SetFileCompletionNotificationModes      更新时间:2023-10-16

我使用SetFileCompletionNotificationModes() API来优化我的I/O完成端口循环,但它似乎不能正常工作。即使我设置FILE_SKIP_COMPLETION_PORT_ON_SUCCESS为套接字和句柄,一个I/O端口的完成回调仍然被调用,如果ReadFile() WriteFile() WSARecv() WSASend()确实返回同步

我确信MSDN说的3个条件必须是真的(一个完成端口与文件句柄相关联,文件为异步I/O打开,请求立即返回成功而不返回ERROR_PENDING)都满足,并且都是真的,所以为什么我仍然收到I/O完成调用?

当我调用SetFileCompletionNotificationModes()时,它返回成功,所以没有错误或任何东西,系统是Windows 7。

我如何复制一个场景,当我在我的套接字/句柄上激活SetFileCompletionNotificationModes()后,我可以清楚地看到I/O完成回调不会被调用?

我猜它发生在我在套接字上写几个字节时,因为套接字的缓冲区相当大,我没有填满它,所以另一个写几个字节不应该阻塞,因为缓冲区中仍然有很多空间,所以它应该立即返回,但不是ERROR_IO_PENDING,只是以同步的方式,对吧?(或多或少,在unix EWOULDBLOCK/EAGAIN类似的方式:当我调用write()几个字节时,它立即返回,而不返回EAGAIN,因为在写缓冲区中仍有空间)。

它不会那样做。即使在套接字上多次写入几个字节,它仍然调用I/O完成回调,从而避免了设置FILE_SKIP_COMPLETION_PORT_ON_SUCCESS

的好处

我错过了什么重要的东西吗?有什么线索吗?

注意:我知道如果套接字只与返回可安装文件系统(IFS)句柄的分层服务提供者(LSP)兼容,这将不起作用,但这不是我的情况,它应该工作。顺便说一句,我也在尝试管道和文件。

不应该文件永远调用I/O完成回调,因为他们从不阻塞,就像在unix read()write()调用本地文件永远不会返回EWOULDBLOCK/EAGAIN,所以ReadFile()WriteFile()与FILE_SKIP_COMPLETION_PORT_ON_SUCCESS句柄设置应该立即返回?

只有当网络堆栈不再需要您提供的数据缓冲区时,才会生成网络写完成。很难推断出什么时候会发生,而且这也不相关,不需要担心。当您使用FILE_SKIP_COMPLETION_PORT_ON_SUCCESS设置发出重叠写操作时,当且仅当同步完成时,您的写操作将返回0。编写代码来正确处理这种情况(与接收端需要的代码相同),然后忘记它。在可能的情况下,您将获得性能和上下文切换的优势,而在不可能的情况下,您的代码将正常工作。

至于文件系统访问,这取决于文件系统驱动程序,可能还取决于实际的硬件。有关让某些硬件执行异步文件写入有多困难的信息,请参阅此处。然后请注意,当我将测试从具有"正常"SATA磁盘的工作站切换到具有硬件raid的服务器时,一切都不同了,所有写操作始终是完全异步的…

确保您验证了文档中提到的第四个条件:

当FileHandle参数为套接字时,此模式只兼容返回IFS句柄的LSP (Layered Service Providers)。使用WSAEnumProtocols函数检测是否安装了非ifs LSP,并检查每个返回的WSAPROTOCOL_INFO结构中的dwServiceFlag1成员。如果清除XP1_IFS_HANDLES (0x20000)位,则该LSP不是IFS LSP。建议拥有非ifs lsp的供应商迁移到Windows过滤平台(WFP)。

也请阅读此MSDN支持票据:

SetFileCompletionNotificationModes API导致安装非ifs LSP时I/O完成端口不能正常工作