IO 完成端口和重叠管理

Posted

技术标签:

【中文标题】IO 完成端口和重叠管理【英文标题】:IO Completion Ports and OVERLAPPED management 【发布时间】:2013-08-14 12:40:01 【问题描述】:

win32 如何在两个函数的上下文中管理 OVERLAPPED 结构的实例:

GetQueuedCompletionStatus
PostQueuedCompletionStatus

    当我调用 GetQueuedCompletionStatus 时,WIN32 免费实例是 OVERLAPPED 结构还是我必须自己做?

    当我使用 PostQueuedCompletionStatus 发送数据时,win32 是否会将其复制到内部结构?何时必须释放已发送数据的内存?

    在哪里可以找到一些在 GetQueuedCompletionStatus、PostQueuedCompletionStatus 和 IOCP 队列之间处理重叠数据的方案的图片?

【问题讨论】:

【参考方案1】:

OVERLAPPED 结构必须存在,从成功执行 I/O 操作(或手动 PostQueuedCompletionStatus())到调用 GetQueuedCompletionStatus() 出现 OVERLAPPED

您对结构的生命周期负责。

您将从 MSDN 文档中看到 GetQueuedCompletionStatus() 实际上采用“一个指向变量的指针,该变量接收在启动完成的 I/O 操作时指定的 OVERLAPPED 结构的地址。”。您实际上从该调用中得到的是一个指向您在进行 PostQueuedCompletionStatus() 调用(或启动重叠 I/O 操作)时传递的原始 OVERLAPPED 的指针。

这实际上非常有用,因为使用 OVERLAPPED 结构的“正常”方式是将其放置在一个更大的结构中,该结构包含您可能需要的所有“每次操作”信息 - 所以这是理想的方式直接从您在调用 GetQueuedCompletionStatus() 时获得的有限信息导航到您在重叠读取调用中使用的数据缓冲区...

我发现处理OVERLAPPED 结构的最佳方法是 a) 将它们嵌入到用于读/写的缓冲区中 b) 对它们进行引用计数和 c) 在引用时将它们返回到池中以供重用计数降至 0。

我有一些你可以下载的源代码 (here),这可能会让这更容易理解(这是一个完整的 IOCP 服务器示例,所以它有点复杂,但它可以工作并展示了如何使用这些东西)。

【讨论】:

Len 请告诉我是否调用 PostQueuedCompletionStatus() 是由操作系统而不是由我进行的,那么我必须在 GetQueuedCompletionStatus() 之后释放收到的数据吗?或者在这种情况下我不是它的所有者?通过调用操作系统,我的意思是例如可以是文件已更改的消息。 调用 GetQueuedCompletionStatus() 产生的所有 OVERLAPPED 结构在某个时候最初归您所有。您将调用一个函数,例如WSARecv()ReadDirectoryChangesW(),并传入OVERLAPPED。没有任何情况(据我所知)您可以调用 API 导致使用最初不是由您提供的 OVERLAPPED 完成。【参考方案2】:
    您应该将OVERLAPPED * 的地址传递给GetQueuedCompletionStatus。这将填充传递给PostQueuedCompletionStatus 的值。 您不应在PostQueuedCompletionStatus 上下文中释放此数据。它应该通过使用GetQueuedCompletionStatus 的上下文来完成。 (假设它首先是动态分配的 - 不需要它是动态分配的结构,它可以从固定池中取出,或者分配在一个函数的堆栈上,直到它有已发出操作完成的信号)。 我不确定是否有这样的图片。

【讨论】:

垫子谢谢!据我了解,默认情况下,我必须只释放我自己的数据(我由 PostQueuedCompletionStatus 发送)并且只能在 GetQueuedCompletionStatus 之后释放?

以上是关于IO 完成端口和重叠管理的主要内容,如果未能解决你的问题,请参考以下文章

Socket编程模型之完成端口模型

UDP.6.重叠IO模型:完成例程

重叠 I/O:如何在完成端口事件或正常事件上唤醒线程?

UDP.07.完成端口模型

IO 完成端口初始读取和双向数据

完成端口与高性能服务器程序开发