IOCP 有自己的内部线程池吗?
没有。如果您自行创建 IOCP (KQUEUE) - 您需要自行调用 GetQueuedCompletionStatus[Ex] (ZwRemoveIoCompletion[Ex])。从哪个线程 - 完全是你的任务。所以在这里你需要自己创建一些“线程池”,它将从 IOCP 弹出数据包并处理它。
如果您将系统 api 用于线程池 - 它在内部使用 IOCP,但您从不直接访问 IOCP - 甚至无法处理它。这一切都在系统上——创建 IOCP、创建线程池、监听 IOCP、调用回调。在这个方案中 - 你自己从 IOCP 弹出数据包 - 注册一些回调 - 当从 IOCP 弹出数据包时系统调用。
例如 - BindIoCompletionCallback
将线程池拥有的 I/O 完成端口与指定的文件句柄相关联。
注意 - 线程池拥有的 I/O 完成端口,而不是 I/O 完成端口拥有的线程池
但是在这个 api 中 - 没有 IOcp 句柄作为参数。默认(因为这里没有办法指定另一个池)系统使用的线程池。它是iocp。如果文件对象在此 api 调用之后保存了指向 iocp 的指针并且当 I/O 完成时 - 数据包将排队到此 iocp,系统池弹出此数据包并调用您的回调。
或CreateThreadpoolIo - 与BindIoCompletionCallback 做同样的事情 - 将线程池拥有的 I/O 完成端口与指定的文件句柄相关联。
但是这里写的不是最好的方式
创建一个新的 I/O 完成对象。
你可能认为新的 IOCP 是通过调用这个 api 创建的。但不是。一些用户模式结构 - 是的,但不是新的 IOCP。对象!=这里的端口。 IOCP 是每个线程池一个,并且只创建一次。通过这个 api。
CreateThreadpool
分配一个新的线程池来执行回调。
作为此任务的一部分 - 创建一个新的 I/O 完成端口。如此间接 - 通过创建新池 - 您创建新的 IOCP(尽管从未直接访问它)。那么你需要:
要使用池,您必须将池与回调环境相关联。要创建回调环境,请调用
初始化线程池环境。然后,调用 SetThreadpoolCallbackPool
将池与回调环境相关联。
然后你可以将这个回调环境传递给CreateThreadpoolIo。所以这个 api 和更老的BindIoCompletionCallback 之间的主要区别是 - 你不能在这里使用默认线程池。但是在大多数情况下,我认为 - 进程中仅使用单个默认线程池。
一般来说 - 如果您自己创建 IOCP - 您需要自己管理它并创建专用线程,用于从 IOCP 弹出数据包 - 这就是所谓的“线程池”
或者您可以使用系统池。在这种情况下,您根本不会直接访问 IOCP。尽管这可能没有直接记录 - 每个线程池仅存在一个 IOCP。如果您使用默认的仅进程线程池 - 您也使用单个 IOCP。如果您创建额外的线程池 - 间接创建额外的 IOCP。
和 IOCP - 不要自行创建任何线程。像事件对象 - 不创建线程,将等待此事件