SetFileCompletionNotificationModes似乎无法正常工作

时间:2014-03-24 18:20:57

标签: c++ sockets winapi io iocp

我使用SetFileCompletionNotificationModes() API来优化我的I / O完成端口循环,但似乎无法正常工作。 即使我为套接字和HANDLE设置了FILE_SKIP_COMPLETION_PORT_ON_SUCCESS,如果ReadFile() WriteFile() WSARecv() WSASend()返回 synchronosly

我确定MSDN所说的3个条件必须为true(完成端口与文件句柄相关联,文件为异步I / O打开,请求立即返回成功而不返回ERROR_PENDING)遇到了,都是真的,为什么我仍然收到I / O完成电话?

当我呼叫SetFileCompletionNotificationModes()时,它会返回成功,因此没有错误或任何错误,系统是Windows 7。

在我的socket / HANDLEs上激活SetFileCompletionNotificationModes()后,如何复制场景,我可以清楚地看到I / O完成回调不会被调用?

我猜想当我在套接字上写几个字节时就会发生这种情况,因为套接字的缓冲区非常大,我没有把它填满,所以另外几个字节的另一个写入不应该是#t阻止,因为缓冲区中仍然有很多空间,所以它应该立即返回,而不是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一样,所以{{1句柄设置为FILE_SKIP_COMPLETION_PORT_ON_SUCCESS并且ReadFile()应该立即返回?

2 个答案:

答案 0 :(得分:2)

只有当网络堆栈不再需要您提供的数据缓冲区时,才会生成网络写入完成。这将是什么时候有点难以理解,而且它也有点无关紧要而且不用担心。当您使用FILE_SKIP_COMPLETION_PORT_ON_SUCCESS设置发出重叠写入时,当且仅当同步发生完成时,写操作将返回0。编写正确处理该案例的代码(它与recv方面所需的代码相同)并忘记它。您可以在可能的情况下获得性能和上下文切换的优势,并且当代码无法正常工作时,您将获得正确的工作。

对于文件系统访问,这取决于文件系统驱动程序,可能还取决于实际的硬件。请参阅here,了解有关使用某些硬件完全执行异步文件写入的难度的一些信息。然后请注意,当我从具有“正常”工作站的工作站切换我所谈论的测试时。 SATA磁盘到服务器的硬件raid一切都不一样,所有的写入总是完全异步...

答案 1 :(得分:1)

确保验证documentation中提到的第4个条件:

  

当FileHandle参数是套接字时,此模式仅与返回可安装文件系统(IFS)句柄的分层服务提供程序(LSP)兼容。检测是否安装了非IFS LSP ,使用WSAEnumProtocols函数并检查每个返回的WSAPROTOCOL_INFO结构中的dwServiceFlag1成员。如果清除XP1_IFS_HANDLES(0x20000)位,则指定的LSP不是IFS LSP。鼓励具有非IFS LSP的供应商迁移到Windows过滤平台(WFP)。

另请阅读此MSDN支持票证:

SetFileCompletionNotificationModes API causes an I/O completion port not to work correctly if a non-IFS LSP is installed