2

关于CreateIoCompletionPort 中并发线程数的选定答案,我对 I/O 完成端口文档中“可运行线程”的定义有疑问:

当与完成端口关联的可运行线程的总数达到并发值时,系统会阻止与该完成端口关联的任何后续线程的执行,直到可运行线程的数量下降到并发值以下。

我了解GetQueuedCompletionStatus()由于发布完成数据包而被唤醒的线程可能会由于其他原因而发现自己处于睡眠状态(即,它尚未完成其工作并且尚未返回调用GetQueuedCompletionStatus(),但正在睡眠,因此 - 如果我正确理解 -根据上述定义无法运行)。

我特别想知道的是:假设上面的线程在其处理过程中正在休眠,因为它产生了另一个线程并正在等待另一个线程完成?

如果线程的子线程处于可运行状态,该线程是否会被视为处于“可运行”状态?

如果没有,似乎无法从与完成端口关联的线程中生成工作线程,而不冒其他线程将被唤醒的危险,这样运行线程的总数就会超过NumberOfConcurrentThreads.

例如 - 假设我有 50 个线程在等待GetQueuedCompletionStatus(),并发线程数为 5,同时发布 20 个完成数据包触发非常长的任务,并且每次线程唤醒执行其中一个任务时,它立即产生一个新的线程完成工作并等待该线程完成长任务,然后再次返回调用GetQueuedCompletionStatus()

在这个例子中,20 个线程会被唤醒并产生 20 个并行工作的子线程,还是只有 5 个线程?

(注意:附录:在我的特定情况下,我正在使用 Boost.Asio 实现一个工作线程池 - 它在内部利用 I/O 完成端口 - 我的工作线程使用 JNI 调用 Java;在内部,Java 代码产生了自己的工作线程 - 所以这是我关心的问题。)

4

1 回答 1

1

寻找此类问题答案的地方始终是 Jeffrey Richter 和 Christophe Nasarre 的“ Windows Via C/C++ (PRO-Developer) ”。

在我的副本的第 327 页上,它清楚地解释了 I/O 完成端口跟踪它从调用(或等效)释放的线程的线程 id,GetQueuedCompletionStatus()并且只要它们不调用任何线程,就将这些线程计为“正在运行”使它们处于等待状态的功能。

因此,在您的示例中,假设调用的线程GetQueuedCompletionStatus()正在等待由 JNI 创建的线程,则该线程被视为“未运行”,因此 IOCP 可以释放另一个线程GetQueuedCompletionStatus()来服务请求。如果您的所有线程最终都将调用 JNI 并创建另一个线程,那么我认为您的设计存在问题,因为您基本上是在创建一个“每个事件线程”设计,该设计可能无法扩展,而 IOCP 设计则不能'不要创建外部线程...

它是生成线程的 JNI 层的函数,还是纯粹在您调用的 Java 代码中?如果是后者,那么我建议尽可能重新设计java代码......

于 2012-11-17T17:27:11.407 回答