线程池
Windows API的线程池函数

Windows操作系统的API提供了一套线程池的实现接口。可以方便地创建、使用线程池。Windows线程池API被设计为一组协同对象， 其中有些对象表示工作单位、计时器、异步I/O 等等。使用下述用户模式的对象来管理线程池及相关的数据：
线程池对象（pool object）包含了一组工作线程（worker threads）。每个进程可以创建多个线程池对象，也可以直接使用进程缺省的线程池。
回调环境(Threadpool Callback Environment)线程池可以关联多个回调环境，回调环境可单独指定在线程池内的调度优先级。
清理群（clean-up group）对象关联于一个回调环境。用于追溯(track)线程缓冲池回调。每次创建线程池的IO、work、timer、wait等对象（调用CreateThreadpool*等函数），会在cleanup group中增加一个成员。关闭线程池的IO、work、timer、wait等对象（调用CloseThreadpool*等函数），会在cleanup group中删除相应的成员。
线程池工作对象（work object） 由一个函数指针和一个被称为上下文的 void 指针组成，线程池每次在执行时将 void 指针送入函数。可异步多次投寄给线程池去执行它的回调函数。实际上就是以异步方式调用回调函数。通过SubmitThreadpoolWork投寄工作对象到任务队列。如果不创建新的工作对象，则不能更改函数和上下文。
线程池定时器对象（timer object）在定时器到期时投寄给线程池去执行它的回调函数。 创建(CreateThreadpoolTimer)并设定(SetThreadpoolTimer)定时器对象。当定时器对象到期时，工作线程会执行定时器对象的回调函数。
线程池等待对象（wait object）：在可等待句柄（waitable handle，可使用任何内核同步对象的句柄）被触发（signaled）时或超时到期时，它的回调函数被投寄给线程池去执行。创建(CreateThreadpoolWait)并设定(SetThreadpoolWait)等待对象。线程池内部的一个线程调用WaitForMultipleObjects并传入由SetThreadpoolWait函数注册的句柄，不断地组成一个句柄组，同时将Wait*函数的bWaitAll设为FALSE，这样当任何一个句柄被触发，线程池就会被唤醒。因WaitForMultipleObjects不允许将同一个句柄传入多次，因此必须确保不会用SetThreadpoolWait来多次注册同一个句柄，但可以调用DuplicationHandle复制句柄并传给Set*函数。因WaitForMultipleObjects一次最多只能等待64个内核对象，因此线程池实际上为每64个内核对象分配一个线程来等待，所以效率比较高。如果要等待超过64个以上的内核对象，系统会每64个内核对象，就开辟一个线程来等待这些内核对象。当线程池中一个线程调用了传入的回调函数，对应的等待项将进入“不活跃”状态；这意味着如果在同一个内核对象被触发后如果想再次调用这个回调函数，需要调用SetThreadpoolWait再次注册；如果传入的hObject为NULL，将把pWaitItem这个等待项从线程中移除。
线程池I/O对象把文件句柄关联到线程池的I/O完成端口（completion port）。当异步I/O操作完成，一个工作线程取得操作的状态并调用I/O对象的回调函数。
相关的API函数：
CreateThreadpool 创建一个线程池数据结构
CloseThreadpool  关闭一个线程池
SetThreadpoolThreadMaximum 设置一个线程池的线程数量上限。默认线程池的最小数量为1，最大数量为500
SetThreadpoolThreadMinimum 设置一个线程池的线程数量下限
InitializeThreadpoolEnvironment 初始化一个回调环境。作用是回调环境结构体中的将Version设为1，其余为0。
DestroyThreadpoolEnvironment 删除回调环境
SetThreadpoolCallbackPool 把指定的线程缓冲池关联到指定的线程池回调环境。创建线程池的IO、work、timer、wait等对象会关联到一个回调环境上。如果使用系统默认的回调环境，需要自行负责回调函数的DLL保持装入状态，自行管理线程池内的各种对象的生存期。线程池可以关联多个回调环境，回调环境可单独指定在线程池内的调度优先级。
SetThreadpoolCallbackLibrary  指示在回调函数未执行完的时候其所在的DLL库不能卸载
SetThreadpoolCallbackPriority 设定回调环境在所属线程池内的优先级
SetThreadpoolCallbackRunsLong 指示当前回调函数将运行较长时间。这有助于线程池判断是否创建新线程
CreateThreadpoolCleanupGroup 创建一个cleanup group数据结构，关联到一个回调环境上
SetThreadpoolCallbackCleanupGroup 把指定的cleanup group关联到指定的回调环境。第三个参数设置CleanupGroupCancelCallback回调函数。当调用清理组的CloseThreadpoolCleanupGroupmembers函数，并为bCancelPendingCallbacks传入TRUE来清除清理组时，如果此时尚有未被处理的工作项时，则这个回调函数被调用，这个回掉函数的第一个参数pvObjectContext是通过CreateThreadpool*函数传入的pvContext，第二个参数pvCleanupContext是由CloseThreadpoolCleanupGroupMembers的pvCleanupContext参数传入的。
CloseThreadpoolCleanupGroup 关闭一个cleanup group数据结构。cleanup group不能包含任何成员。
CloseThreadpoolCleanupGroupMembers 把指定cleanup group的所有work、timer、wait等对象释放掉。对于正在执行的回调函数，会等待其执行完毕。参数fCancelPendingCallbacks确定是否尚未开始执行的任务执行。
CreateThreadpoolWork 创建一个线程池工作对象的数据结构
CloseThreadpoolWork 函数通知线程池该对象可释放。
SubmitThreadpoolWork 投寄（post）一个工作对象到线程池中。一个工作线程将会调用执行这个工作对象的回调函数。
TrySubmitThreadpoolCallback 请求线程池一个工作线程调用指定的回调函数
CreateThreadpoolTimer 创建一个线程池定时器对象的数据结构
SetThreadpoolTimer 设定一个线程定时器对象的参数。当定时器到期时，这个定时器对象的回调函数被放入任务队列等待被一个工作线程执行。第三个参数设定周期性到时，不论之前放入任务队列的回调函数是否执行完毕，总是把回调函数再一次放入任务队列等待被执行。如果不希望一个定时器对象的回调函数的多个实例并发重叠执行，可以不设定周期性到时参数，而在回调函数末尾调用SetThreadpoolTimer重置这个定时器对象，起码可以简化调试。如果调用SetThreadpoolTimer时当前定时器对象还没有到期，则会修改该定时器对象的到期时间等属性。第二个参数pftDueTime表示首次到时时间，如果为NULL，则取消还未到时的定时器的下次到期，不再向任务队列放入定时器对象的回调函数，但已经在任务队列中（正在被执行）的回调函数仍会被执行。第四个参数是到时的容限上限，涉及定时器汇聚，如计时器A会在5-7微秒内被触发，计时器B会在6-8微秒内。因时间有重叠，所以线程池只会唤醒一个线程来处理这两个计时器，以减少用两个线程调用时产生的额外的线程上下文切换的开销。
IsThreadpoolTimerSet 判断给定的定时器对象当前是否被设置
CreateThreadpoolWait 创建一个线程池等待（wait）对象的数据结构
SetThreadpoolWait 设定一个线程等待对象与一个可等待对象(waitable object)的句柄绑定并设定超时时间。当可等待对象的句柄被通知(signaled)或指定的超时到期，这个等待对象的回调函数会被入列（queue）进入任务队列中并等待被一个工作线程执行。如果可等待对象（即函数的第二个参数）的句柄被设置为NULL，（由于可等待对象还没有signaled所以）线程池等待对象的回调函数还未放入任务队列的都被取消，但已在任务队列的回调函数仍会被工作线程执行。注意不要多次使用SetThreadpoolWait来等待同一个hObject。第三个参数pftTimeout指出线程池愿意花的最长时间来等待内核对象触发，0是立即返回，负值为相对时间，正值为绝对时间，NULL表示无限等待（线程池内部调用了WaitForMultipleObjects）。
CloseThreadpoolWait 关闭一个线程等待对象，然后才能关闭可等待对象(waitable object)的句柄。
WaitForThreadpoolWaitCallbacks 等待指定的线程池等待对象执行完成或者取消还没开始执行的线程池等待对象。
WaitForThreadpoolIoCallbacks 等待指定的线程池IO对象执行完成或者取消还没开始执行的线程池IO对象。该函数须在另一个线程使用，而不能在回调函数内部使用，因为这会造成死锁。如果bCancelPendingCallbacks为TRUE，那么当请求完成的时候，回调函数不会被调用（如果尚未被调用）。
WaitForThreadpoolTimerCallbacks 等待指定的线程池定时器对象执行完成或者取消还没开始执行的线程池定时器对象。
WaitForThreadpoolWorkCallbacks 等待指定的线程池工作对象执行完成或者取消还没开始执行的线程池工作对象。
CreateThreadpoolIo 创建一个IO完成对象，并绑定一个异步IO的句柄。
CloseThreadpoolIo 释放IO完成对象。应等待所有IO操作完成，关闭IO文件句柄后再调用本函数。解除IO对象（工作项）与线程池的关联。
StartThreadpoolIo 初始化异步IO操作前应先调用本函数，否则线程池会忽略IO操作的完成并内存泄露。
CancelThreadpoolIo 在IO失败或者IO直接同步完成时，取消对线程池的通知（notification）
CallbackMayRunLong 回调函数通知系统需要执行较长时间。只能在调用线程的回调函数里使用。返回TRUE时，说明线程池还有其他线程可供使用。FALSE则相反。
DisassociateCurrentThreadFromCallback 表示与回调函数关联的工作项在“逻辑上”完成了，执行当前回调函数的线程与初始化当前回调函数的对象去关联。这使得所有等待当前回调函数完成的线程被释放。任何由于调用WaitForThreadpool*Callbacks（如WaitForThreadpoolIoCallbacks）而被阻塞的线程能早一些返回，而不必等到线程从回调函数中结束时才返回。
下述函数与回调函数实体指针PTP_CALLBACK_INSTANCE有关，用于在回调函数内设置当该函数结束时的动作。注意只能有一个动作在回调函数结束后被执行，不能多次调用下述函数，否则最后一次调用的函数会覆盖之前调用的下述函数。当线程调用回调函数时，Windows会自动传一个pInstance参数（类型PTP_CALLBACK_INSTANCE)给回调函数，然后回调函数将这个参数又传给如下的函数，执行一些相应的终止操作：
FreeLibraryWhenCallbackReturns 当回调函数返回的时候，线程池会自动调用FreeLibrary，并在参数中传入指定的HMOUDLE。如果回调函数是从DLL中载入的，这个函数尤为重要，因为当线程执行完毕后，回调函数不能自己调用FreeLibrary，否则回调函数代码将从进程中清除，这样当FreeLibrary试图返回到回调函数时，会引发访问违规
LeaveCriticalSectionWhenCallbackReturns 当回调函数返回时，线程池会自动调用LeavCriticalSection，并在参数中传入指定的CRITCAL_SECTION结构体。
ReleaseMutexWhenCallbackReturns 当回调函数返回时，线程池会自动调用ReleaseMutex，并在参数中传入指定的HANDLE
ReleaseSemaphoreWhenCallbackReturns 当回调函数返回的时候，线程池会自动调用ReleaseSemaphore，并在参数中传入指定的HANDLE
SetEventWhenCallbackReturns 当回调函数返回的时候，线程池会自动调用SetEvent，并在参数中传入指定的HANDLE