windows - IOCP 循环终止可能导致内存泄漏?如何优雅地关闭 IOCP 循环

标签 windows multithreading io iocp

我有经典的 IOCP 回调,它以这种方式使 i/o 挂起的请求出列、处理它们并释放它们:

struct MyIoRequest { OVERLAPPED o; /* ... other params ... */ };
bool is_iocp_active = true;

DWORD WINAPI WorkerProc(LPVOID lpParam)
{
    ULONG_PTR dwKey;
    DWORD dwTrans;
    LPOVERLAPPED io_req;
    while(is_iocp_active)
    {
        GetQueuedCompletionStatus((HANDLE)lpParam, &dwTrans, &dwKey, (LPOVERLAPPED*)&io_req, WSA_INFINITE); 
       // NOTE, i could use GetQueuedCompletionStatusEx() here ^ and set it in the 
       // alertable state TRUE, so i can wake up the thread with an ACP request from another thread!

        printf("dequeued an i/o request\n");
        // [ process i/o request ]
        ...

        // [ destroy request ]
        destroy_request(io_req);
    }
    // [ clean up some stuff ] 
    return 0;
}

然后,在代码中我会在某处:

MyIoRequest * io_req = allocate_request(...params...);
ReadFile(..., (OVERLAPPED*)io_req);

这非常有效。

现在我的问题是:我想立即关闭 IOCP 队列而不造成泄漏怎么办? (例如应用程序必须退出) 我的意思是:如果我将 is_iocp_active 设置为“false”,下一次 GetQueuedCompletionStatus() 将出列一个新的 i/o 请求,这将是最后一个 i/o 请求:它将返回,导致线程退出以及线程退出时根据 MSDN,所有挂起的 i/o 请求都被系统简单地取消了。

但是我在调​​用 ReadFile() 时实例化的“MyIoRequest”类型的结构根本不会被销毁:系统已经取消了挂起的 i/o 请求,但我必须手动销毁我拥有的那些结构 创建,否则我将在停止循环时泄漏所有未决的 i/o 请求!

那么,我该怎么做呢?仅仅将该变量设置为 false 来停止 IOCP 循环是错误的吗?请注意,即使我使用 APC 请求来停止可警告的线程,也会发生这种情况。

我想到的解决方案是将每个“MyIoRequest”结构添加到队列/列表,然后在 GetQueuedCompletionStatusEx 返回时将它们出队,但这不应该造成一些瓶颈,因为此类 MyIoRequest 的入队/出队过程结构必须互锁?也许我误解了如何使用 IOCP 循环。有人可以阐明这个主题吗?

最佳答案

我通常关闭 IOCP 线程的方式是发布我自己的“请立即关闭”完成。这样您就可以干净地关闭并处理所有未决的完成,然后关闭线程。

执行此操作的方法是调用 PostQueuedCompletionStatus(),其中 num 个字节、完成键和 pOverlapped 为 0。这将意味着完成键是一个唯一值(你不会有一个有效的文件或套接字具有零句柄/完成键)。

第一步是关闭完成源,因此关闭或中止套接字连接、关闭文件等。一旦所有这些都关闭,您就无法再生成任何完成数据包,因此您可以发布特殊的 '0 '完成;为您为 IOCP 提供服务的每个线程发布一个。一旦线程获得“0”完成键,它就会退出。

关于windows - IOCP 循环终止可能导致内存泄漏?如何优雅地关闭 IOCP 循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15547741/

相关文章:

c# - 在 Windows 中以兼容模式启动应用程序如何影响该应用程序以及我如何检测它?

windows - Windows Azure 能否随着负载变化动态扩展应用程序?

java - 检查另一个用户是否有写文件的权限

c - SDL_Thread 的存储大小未知?

java - 我如何用 Java 编写一个信号量来优先考虑以前成功的申请人?

c# - 启动 "background"Windows 应用程序

无限迭代器上的Python线程/进程池?

haskell - 继续进入元组

ios - 不使用任何 Apple API 加载 GLSL 着色器

c++ - 在类和类的标题中重载 << 运算符时遇到问题