我有一个经典的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请求:它将返回,导致线程退出,并且当一个线程退出时,系统将简单地取消所有挂起的i/o请求。
但我在调用ReadFile()时实例化的'MyIoRequest‘类型的结构根本不会被销毁:系统已经取消了挂起的i/o请求,但我必须手动销毁我创建的那些结构,否则当我停止循环时,我将泄漏所有挂起的i/o请求!
那么,我该怎么做呢?仅仅将该变量设置为false来停止IOCP循环是错误的吗?请注意,即使我使用APC请求来停止可警报线程,也会发生这种情况。
我想到的解决方案是将每个“MyIoRequest”结构添加到一个队列/列表中,然后在GetQueuedCompletionStatusEx返回时将它们出队,但这不应该造成一些瓶颈吗,因为这样的MyIoRequest结构的入队/出队过程必须是互锁的?也许我误解了如何使用IOCP循环。有人能给这个话题带来一些启发吗?
发布于 2013-03-22 16:37:07
我通常关闭IOCP线程的方式是发布我自己的“请立即关闭”的完成。这样,您就可以干净利落地关闭并处理所有挂起的完成,然后关闭线程。
这样做的方法是调用PostQueuedCompletionStatus(),其中0表示字节数、完成键和pOverlapped。这意味着完成键是唯一的值(你不会有一个有效的文件或套接字有一个零句柄/完成键)。
第一步是关闭完成的源代码,因此关闭或中止你的套接字连接,关闭文件等。一旦所有这些都关闭了,你就不能再生成任何完成包,所以你可以发布你的特殊“0”完成;为你的IOCP服务的每个线程发布一个完成包。一旦线程获得了一个'0‘完成键,它就会退出。
发布于 2013-03-21 20:55:46
如果您要终止应用程序,并且没有压倒一切的理由不这样做,(例如。关闭数据库连接,进程间共享内存问题),调用ExitProcess(0)。
否则,为所有套接字句柄调用CancelIO(),并在所有取消的完成传入时处理它们。
先试试ExitProcess()吧!
https://stackoverflow.com/questions/15547741
复制相似问题