为什么设置IOCP的numberOfConcurrentThreads为1却有多个线程运行?
IOCP并发数参数与预期不符的原因
核心原因
你对CreateIoCompletionPort最后一个参数NumberOfConcurrentThreads的语义理解存在偏差,且测试代码的处理逻辑存在触发IOCP调度新线程的隐藏等待行为,共同导致了运行结果不符合预期。
参数的真实含义
NumberOfConcurrentThreads限制的是与该IOCP关联、处于可运行状态的线程最大数量,而非以下常见误区:
- 不是限制最多能有多少线程绑定到该IOCP
- 不是限制最多能有多少线程调用
GetQueuedCompletionStatus等待完成包 - 不是限制最多能有多少线程从IOCP获取完成包
IOCP的调度规则为:当正在运行的关联线程进入任何等待状态(包括IO阻塞、等待同步锁、Sleep等)时,该线程会被暂时移出运行计数,IOCP会立刻唤醒下一个等待中的线程,去处理队列中待消费的完成包,直到运行计数达到NumberOfConcurrentThreads设置的阈值。
测试代码的问题
你在拿到完成包后直接执行了while (true) { cout << mO->number << endl; }逻辑,而cout输出到控制台的操作内部存在全局同步锁,且涉及控制台IO操作,每次调用都会让线程短暂进入等待状态:
- 你一次性调用
PostQueuedCompletionStatus投递了5个完成包到队列中 - 第一个线程拿到第一个完成包,开始执行输出逻辑,第一次调用
cout时进入等待状态(等待控制台锁/IO完成) - IOCP检测到当前可运行的关联线程数变为0,立刻唤醒第二个等待线程取下一个完成包
- 以此类推,直到5个完成包全部被不同的线程取走,就出现了你截图中的运行结果
验证方案
你可以将处理逻辑替换为纯用户态无等待的死循环,完全不触发任何系统等待,即可得到符合你预期的结果:
if (success) { myOverlapped* mO = (myOverlapped*)overlappedPointer; // 纯用户态死循环,不会进入任何等待状态 volatile int dummy = 0; while (true) { dummy++; } }
运行上述修改后的代码,你会发现只有1个线程被唤醒,剩余4个线程永远拿不到完成包,符合NumberOfConcurrentThreads=1的限制。
内容的提问来源于stack exchange,提问作者DoyoHntr
相关产品推荐
相关产品推荐

