3

我有经典的 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 循环。有人可以对这个话题有所了解吗?

4

2 回答 2

4

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

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

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

于 2013-03-22T08:37:06.650 回答
-1

如果您要终止应用程序,并且没有理由不这样做(例如关闭数据库连接、进程间共享内存问题),请调用 ExitProcess(0)。

如果做不到这一点,请为所有套接字句柄调用 CancelIO() 并在它们进入时处理所有已取消的完成。

先试试 ExitProcess()!

于 2013-03-21T12:55:46.440 回答