一直很迷惑IOCP是怎么管理线程池的.还有就是GetQueuedCompletionStatus函数和线程池是什么关系,是GetQueuedCompletionStatus通过线程池的线程调用完成请求,还是先调用GetQueuedCompletionStatus得到请求在把请求交给线程池的线程完成的呢?
当你创建一个了IOCP,并指定了能并发运行的线程数目(CPU*2).当完成的I/O项进入队列时,IOCP就要唤醒等待的线程.不过,IOCP只唤醒指定的数目的线程.假设有4个I/O请求完成了,IOCP只唤醒2个线程,另两个线程将继续休眠.可能要问,如果IOCP只能允许唤醒指定数目的线程,那么为什么还要创建多余的线程.原因是:当IOCP唤醒一个线程时,它把线程的ID放在了同它相关联的第4个数据结构(释放线程队列表中).这使的IOCP能记住它唤醒了哪个线程并允许它监视这些线程的执行.如果释放一个线程,就会把这个线程的ID从释放队列移到暂停线程队列中.IOCP的目标是使在释放线程队列表中的线程数与它被创建时指定的并发线程数相同.如果一个释放线程因某种原因进入了等待状态,释放线程列表变小,IOCP就释放另一个等待的线程.如果一个暂停线程唤醒来,它就离开暂停线程列表,重新进入释放线程列表.释放列表中的线程数可能比允许的最大并发线程数要大.
例子:如果端口队列有3个完成的I/O请求,只有两个线程唤醒来处理.如果一个运行的线程调用了Sleep或其他任何使它不能运行的函数.IOCP检测到这一点,就立刻唤醒第3个线程.最终,第一个线程会再次运行.这使的运行的线程数目大于系统中的CPU数目.不过,IOCP会意识到这一点.在线程数目少于CPU数目之前,不会唤醒其他线程.当线程在次调用GetQueuedCompletionStatus时,数目会降下了.
http://blog.csdn.net/youngcs/article/details/1876438
当线程池中的一个线程调用GetQueuedCompletionStatus时,调用线程的ID就会被放入该等待线程队列中.这样,IOCP就知道哪个线程在等待完成I/O的请求.对于IOCP来说,创建一定数量的工作线程是必要的,但不是必须预先创建。通常的资料中会提示您创建cpu核心数x2+2数量的工作者线程。但是请注意:这只是一般情况。 一个线程执行效率是否够高,要看它做了什么和等待了什么。线程在执行一些阻塞操作的时候是会进行等待的,比如等待硬盘I/O,等待串口数据,等待SQL查询结果……在工作线程被阻塞并等待时,操作系统会切换context,选择并将执行权力交给另一个“饥饿”线程。试想一个场景:您的IOCP系统启动时创建了10个工作线程,当某一时刻(比如过年大家都在发短信,而您的系统需要通过串口向短信modem发送和接收数据)大量的需要进行串口数据收发的请求被连入系统,所有10个工作线程全部被排队阻塞在串口短信机收发动作上,这时新的请求就无法及时处理,但您系统的CPU资源其实还有很大富余。只是能够对数据进行处理的工作者线程已经被耗尽。 这个情况该怎么处理呢? 这时您就应当考虑“线程池”的管理模式了。由线程池管理者判断当前工作线程是否还有空闲的(GetQueuedCompletionStatus时应属于空闲)。如果空闲线程已经不足(这个取决于逻辑,比如当前只有0个或2个空闲线程),那么管理者应立即创建新的工作者线程。如果空闲线程太多(比如有20个空闲的),管理者应将多余的线程关闭(PostQueuedCompletionStatus(MY_MSG_EXIT))。 至于您的疑惑:在用IOCP的时候不就是要预先创建一定数量的线程吗,一旦这些线程全部创建完毕,是不是就等价于已经创建了一个线程池了?预先创建并且不能够根据实际需要增加和减少的这些工作线程,只能称为线程组,它们并不是线程池。另外,IOCP也并不是必须在启动时创建一定数量工作线程的,完全可以全部都交给线程池进行判断和管理。启动后当线程池判断空闲工作者不足,则立即进行创建动作。