这两天搞了一下windows thread pool. 有些心得!
windows thread pool 的实现方式.
对于所谓的non-io线程,采用完成端口排队方式. 模拟来说,当调用
queueworkitem,NONIO时候,TP将根据内部的算法将一组线程和一个COMPPORT结合在一起.同时将这些线程在COMPPORT上等待. 然后发送一个postqueuecompletedstatus 包给完成端口,如果完成端口上有空闲的线程,那么就会释放一个线程,被释放的线程实际上一直在调用GetQueueCompletedStatus , 一旦得到返回,那么能够得到PKEY,另外一个就是OVERLAPPED.
现在我的估计queueworkitem传递进入的PCONTEXT,callback 是通过GetqueueCompstatus中获取的LPKEY以及LPOVVERLAPPED获取的. 这样工作线程就能够callback(lpvoid)方式来通知用户了.
added:
假如在回调中使用ALEARTABLE等待,或者sleep那么将导致此线程无法在其退出前被服用,通过我的例子发现TP会初始化分配一定数量的线程,比如=7,然后当这些线程都处于等待状态后,很长一段时间都没有再次分配.
对于 io 线程,采用APC排队方式实现.当用户queueworkitem的时候,TP根据内部算法将callback,LPVOID作为APC派给TP中的一个工作线程,而线程中的工作线程正在以 sleepex或者其它等待方式处于alertable wait状态,一旦 "看到"线程
APC队列中有APC线程立刻被唤醒,执行,反过来说如果这个时候被排队线程正在运行或者没有处于alertable wait状态那么该APC将得不到执行.
added :
因为采用APC进行排队,所以如果在callback中使用ALEARTABLE wait,那么必须注意reentry.
对于CreateTimerQueueTimer来说, 略有区别,如果制定了timer flags表示启动timer线程,而这种线程实际上运行方式有点类似与io线程,也是通过APC排队方式进行,不过区别在于能够利用kernel timer周期性的进行排队,不过这儿有一点需要注意,一旦定时器到时时候该线程没有处于alertable wait状态也就是说线程可能还没有处理完上次APC或者根本没有进入等待,那么本次APC将丢失.
registerwaitforsingleobject 当单个kernel对象变为通知状态时候调用callback.一旦使用这种类型,那么实际上是waitformultipleobject+nonio thread pool结合了依赖,意思就是满足了handle触发的条件就queueworkitem.
由于windows规定waitformultipleobject最多只能等待 64个对象,所以超过 64系统将重新分配一个等待线程等待新的handle.
bindiocompletioncallback 当异步请求完成时候callback .
这个方式实际上是nonio方式的特别类型,不同点在于 postqueuecompletedstatus不是模拟发出,而是通过真正的handle通知发出.
createtimerqueuetimer 将导致出现一个线程,而在这个线程中如果制定了WT_EXECUTEINTIMERTHREAD 那么表示线程内部如果存在sleepex那么将导致reentry问题. 另外这种模式下将仅仅存在一个线程.
当采用WT_EXECUTEINIOTHREAD ,表示将在IO线程中运行,同时又由于排列了定时器,所以定时器的作用就是每隔一段时间发起一个APC。 这种情况下,如果已经启动的纤尘一直没有处于ALERTABLE状态,那么将迫使TP不断的创建线程. 同样这种模式下,如果线程主动进入ALERTABLE状态也将导致reentry情况.
下面这篇文章比较了普通windows threadpool 和managed thread pool 的区别
阅读(1460) | 评论(0) | 转发(0) |