CreateIoCompletionPort
函数允许创build新的I / O完成端口,并将文件句柄注册到现有的I / O完成端口。
然后,我可以使用任何函数,例如套接字上的recv
或具有OVERLAPPED
结构的文件上的ReadFile
来启动asynchronous操作。
我必须检查函数调用是否同步返回,尽pipe它是用OVERLAPPED
结构调用的,在这种情况下直接处理它。 在另一种情况下,当返回ERROR_IO_PENDING
时,我可以使用GetQueuedCompletionStatus
函数在操作完成时得到通知。
出现的问题是:
如何从I / O完成端口中删除句柄? 例如,当我向IOCP添加套接字时,如何删除封闭的套接字? 我是否应该使用相同的完成键重新注册另一个套接字?
另外,有没有办法让电话总是通过I / O完成端口,不要同步返回?
最后,有可能例如recv
asynchronous,但同步send
? 例如,当实现一个简单的echo服务时:我可以用一个asynchronousrecv
等待新数据,但以同步的方式send
响应,以便减less代码复杂性? 就我而言,在处理第一个请求之前,我不会再进行第二次调用。
如果已经请求了一个asynchronousReadFile
,但是在完成之前会发生一个WriteFile
到同一个文件的处理。 ReadFile
是否会被取消,并且一旦写入完成,我必须重新启动读取过程? 或者我必须在写入之前手动取消ReadFile
? 这个问题与通讯设备结合起来。 所以,如果同时发生,写入和读取不应该发生问题。
如何从I / O完成端口中删除句柄?
根据我的经验,您无法取消完成端口的句柄。 但是,可以通过设置OVERLAPPED
结构的hEvent
字段的低位来禁用完成端口通知:请参阅GetQueuedCompletionStatus的文档。
例如,当我向IOCP添加套接字时,如何删除封闭的套接字? 我是否应该使用相同的完成键重新注册另一个套接字?
从I / O完成端口不需要显式地分离句柄; 关闭手柄就足够了。 您可以将多个句柄关联到相同的完成键; 找出哪个请求与I / O完成关联的最好方法是使用OVERLAPPED
结构。 事实上,你甚至可能扩展OVERLAPPED
来存储额外的数据。
另外,有没有办法让电话总是通过I / O完成端口,不要同步返回?
这是默认行为,即使ReadFile
/ WriteFile
返回TRUE
。 您必须显式调用SetFileCompletionNotificationModes来告诉Windows在返回TRUE
和ERROR_SUCCESS
时不排队完成数据包。
有可能例如
recv
异步,但同步send
?
不要使用recv
和send
; 您需要使用接受OVERLAPPED
结构的函数,如WSARecv
, WSASend
或者ReadFile
和WriteFile
。 如果你的代码是用来处理多种类型的I / O句柄,比如套接字和命名管道,那么使用后者可能会更方便一些。 这些功能提供了一个同步模式,所以如果你使用它们,你可以混合使用异步和同步调用。
如果已经请求了一个异步ReadFile,但是在它完成之前会发生一个WriteFile到同一个文件的处理呢?
没有隐含的取消。 只要你使用单独的OVERLAPPED
结构来读/写全双工设备,我没有理由不能做并发I / O操作。
正如我已经指出的那样,人们普遍认为不可能从完成端口中删除句柄是错误的,这可能是由于我几乎找不到所有文档中的任何提示而导致的。 其实,这很简单:
使用FileInformationClass
的FileReplaceCompletionInformation
枚举器值和指向FileInformation
参数的FILE_COMPLETION_INFORMATION
结构的指针调用NtSetInformationFile
。 在这个结构中,将Port
成员设置为NULL
(或C ++中的nullptr
),将文件从当前连接的端口上解除关联(我猜如果没有连接到任何端口,什么都不会发生),或者将Port
设置为一个有效的HANDLE
到另一个完成端口来将文件与那个文件关联起来。
首先一些重要的更正。
如果重叠的I / O操作立即完成( ReadFile
或类似的I / O函数返回成功) – I / O完成已经安排到IOCP。
此外,根据你的问题,我认为你在文件/套接字句柄和在它们上发出的特定I / O操作之间混淆。
现在,关于你的问题:
更正确的问题应该是如何正确关闭文件/套接字。 答案是:关闭你的手柄。 所有未完成的I / O操作(在这个句柄上发出)将很快返回一个错误代码(中止)。 然后,在完成例程(在循环中调用GetQueuedCompletionStatus
例程)应该执行每个I / O所需的清理。
正如我已经说过的,所有I / O完成都在同步和异步情况下到达IOCP。 唯一没有到达IOCP的情况是当一个I / O同时完成一个错误 。 无论如何,如果你想要一个统一的处理 – 在这种情况下,你可以发布人工完成数据到IOCP(使用PostQueuedCompletionStatus
)。
您应该使用WSASend
和WSARecv
(不recv
和send
)重叠的I / O。 不过,即使套接字已经打开了WSA_FLAG_OVERLAPPED
标志 – 你可以调用I / O函数而不指定OVERLAPPED
结构。 在这种情况下,这些功能同步工作。 这样你可以决定每个函数调用的同步/异步模式。
混合重叠的读/写请求没有问题。 唯一微妙的一点是,如果您尝试从当前正在写入的文件位置读取数据,会发生什么情况。 其结果可能依赖于微妙的东西,例如硬件完成I / O的顺序,一些PC定时参数等。这种情况应该避免。
如何从I / O完成端口中删除句柄? 例如,当我向IOCP添加套接字时,如何删除封闭的套接字? 我是否应该使用相同的完成键重新注册另一个套接字?
你有错误的方法。 设置文件对象使用的I / O完成端口 – 当文件对象被删除时,您无需担心。 你感到困惑的原因是因为Win32暴露了底层本地API的功能( CreateIoCompletionPort
在一个函数中做了两个完全不同的事情)。
另外,有没有办法让电话总是通过I / O完成端口,不要同步返回?
这是一直如此。 只有从Windows Vista开始,才能自定义完成通知的处理方式。
如果已经请求了一个异步ReadFile,但是在完成之前会发生一个WriteFile到同一个文件的处理。 ReadFile是否会被取消,并且一旦写入完成,我必须重新启动读取过程?
Windows中的I / O操作本质上是异步的,并且请求总是排队的。 您可能不认为这是因为您必须在CreateFile
指定FILE_FLAG_OVERLAPPED
来打开异步I / O。 然而,在本地层,同步I / O实际上是一个附加的,便利的事情,内核跟踪你的文件位置,并在返回之前等待I / O完成。