线程池

线程池是工作线程的集合,可以代表应用程序有效地执行异步回调。线程池主要用于减少应用程序线程的数量并提供工作线程的管理。应用程序可以对工作项进行排队,将工作与可等待的句柄相关联,根据计时器自动排队,并与I / O绑定。

线程池体系结构

以下应用程序可以从使用线程池中受益:

1. 高度并行的应用程序,可以异步分派大量小工作项(例如分布式索引搜索或网络I / O)。

2. 一个创建和销毁大量线程的应用程序,每个线程都运行一小段时间。使用线程池可以降低线程管理的复杂性以及线程创建和销毁所涉及的开销。

3. 在后台和并行处理独立工作项的应用程序(例如加载多个选项卡)。

4. 必须对内核对象执行独占等待或阻止对象上的传入事件的应用程序。使用线程池可以减少线程管理的复杂性,并通过减少上下文切换的数量来提高性能。

5. 一个创建自定义服务器线程以等待事件的应用程序。

原始线程池已在Windows Vista中完全重新架构。新线程池得到改进,因为它提供单个工作线程类型(支持I / O和非I / O),不使用计时器线程,提供单个计时器队列,并提供专用的持久线程。它还提供清理组,更高的性能,独立调度的每个进程的多个池以及新的线程池API。线程池体系结构包括以下内容:

1. 执行回调函数的工作线程

2. 等待多个等待句柄的服务器线程

3. 工作队列

4. 每个进程的默认线程池

5. 管理工作线程的工作者工厂

Best Practices

新线程池API提供比原始线程池API更具灵活性和控制力。但是,有一些微妙但重要的差异。在原始API中,等待重置是自动的;在新的API中,每次都必须显式重置等待。原始API自动处理模拟,将调用进程的安全上下文传递给线程。使用新API,应用程序必须显式设置安全上下文。

以下是使用线程池时的一些best practice:

1. 进程的线程共享线程池。单个工作线程可以执行多个回调函数,一次一个。这些工作线程由线程池管理。因此,不要通过在线程池中的线程上调用TerminateThread,以终止线程或通过从回调函数调用ExitThread来终止线程池中的线程。

2. I / O请求可以在线程池中的任何线程上运行。取消线程池线程上的I / O需要同步,因为取消功能可能在与处理I / O请求的线程不同的线程上运行,这可能导致取消未知操作。为避免这种情况,为异步I / O调用CancelIoEx时启动I / O请求,请始终提供OVERLAPPED结构,或使用您自己的同步确保在调用CancelSynchronousIo或CancelIoEx函数之前不能在目标线程上启动其他I / O. 。

3. 在从函数返回之前清除在回调函数中创建的所有资源。这些包括TLS,安全上下文,线程优先级和COM注册。回调函数还必须在返回之前恢复线程状态。

4. 保持等待句柄及其关联对象保持活动状态,直到线程池发出信号表示已完成该句柄相关的工作为止。

5. 标记正在等待冗长操作的所有线程(例如I / O刷新或资源清理),以便线程池可以分配新线程而不是等待这个线程。

6. 在卸载使用线程池的DLL之前,取消所有工作项,I / O,等待操作和计时器,并等待执行回调完成。

7. 通过消除工作项之间和回调之间的依赖关系,确保回调不等待自身完成,以及保留线程优先级,来避免死锁。

8. 在有使用默认线程池的其他组件的进程中,不要太快地排队太多项目。每个进程有一个默认线程池,包括Svchost.exe。默认情况下,每个线程池最多包含500个工作线程。当处于就绪/运行状态的工作线程数必须小于处理器数时,线程池会尝试创建更多工作线程。

9. 避免使用COM单线程套间模型,因为它与线程池不兼容。 STA创建的线程状态,可以影响线程的下一个工作项。 STA通常是长寿的并且具有线程亲和性,这和线程池相反

10. 创建新的线程池以控制线程优先级和隔离,创建自定义特征,并可能提高响应能力。但是,额外的线程池需要更多系统资源(线程,内核内存)。池太多会增加CPU竞争的可能性。

11. 如果可能,使用可等待的对象而不是基于APC的机制来触发线程池线程。 APC不像其他通知机制一样和线程池线程兼容,因为系统控制线程池线程的生命周期,因此可以在传递通知之前终止线程。

12. 使用线程池调试器扩展名!tp。此命令具有以下用法:

      1. 池地址标志

       2. obj地址标志

       3. tqueue地址标志

       4. waiter地址

       5. 工作程序地址

对于池,waiter和worker,如果地址为零,则命令转储所有对象。对于waiter和woker,省略地址会转储当前线程。定义了以下标志:0x1(单行输出),0x2(转储成员)和0x4(转储池工作队列)。

线程池API

线程池API 使用基于对象的设计。下面的每个结构都代表一个用户模式数据结构

1. pool object,一系列可以用来执行工作的工作线程。每个进程可以按需创建多个隔离的拥有不同属性的池。每个进程有一个默认的池

2. 一个clean-up group,绑定一系列callback-generating objects。存在等待并释放每个clean-up group 成员的所有的对象的函数。这使应用程序无需跟踪它创建的所有对象。

3. 工作对象,与一个池绑定,可选的跟clean-up group 绑定。它可以被posted,使pool 中的一个工作线程区执行它的callback。一个工作对象可以有多个post outstanding(多个post 未完成?)。每个都会产生一个回调。post 操作不会因为缺乏资源失败。

4. 定时器对象控制callback 的调度。每次一个定时器到期,它的callback 被post 到它的工作池。设置定时器不会因为缺乏资源失败。

5. 一个等待对象,导致一个工作线程在可等待的句柄上等待。等待被满足或超时到期,工作线程将等待对象的callback post 到等待者的工作池。设置一个等待,不会因为缺乏资源失败。

6. I/O 对象为线程池将一个文件句柄和I/O 完成端口关联。当一个异步I/O 操作完成,一个工作线程提取操作的状态,并调用I/O 对象的callback。

下面的表描述了之前和现在的线程池的API

https://docs.microsoft.com/en-us/windows/desktop/procthread/thread-pool-api

Thread Pooling

https://docs.microsoft.com/en-us/windows/desktop/procthread/thread-pooling

有许多应用程序创建线程,在休眠状态下花费大量时间等待事件发生。其他线程可以进入休眠状态,仅定期唤醒以轮询更改或更新状态信息。线程池使您可以通过为应用程序提供由系统管理的工作线程池来更有效地使用线程。至少有一个线程监视排队到线程池的所有等待操作的状态。等待操作完成后,来自线程池的工作线程执行相应的回调函数。

本主题描述了原始线程池API。 Windows Vista中引入的线程池API更简单,更可靠,性能更好,并为开发人员提供了更大的灵活性。

您还可以将与等待操作无关的工作项排队到线程池。要请求线程池中的线程处理工作项,请调用QueueUserWorkItem函数。此函数接受一个传递给,从线程池中选择的线程调用的函数,的参数。排队后无法取消工作项。

定时器队列定时器和注册的等待操作也使用线程池。它们的回调函数排队到线程池。您还可以使用BindIoCompletionCallback函数发布异步I / O操作。完成I / O后,回调由线程池线程执行。

线程池是在您第一次调用QueueUserWorkItem或BindIoCompletionCallback时创建的,或者是在计时器队列计时器或已注册的等待操作对回调函数进行排队时创建的。默认情况下,可以在线程池中创建的线程数约为500.每个线程使用默认堆栈大小并以默认优先级运行。

线程池中有两种类型的工作线程:I / O和非I / O. I / O工作线程是一个等待处于可警告等待状态的线程。工作项作为异步过程调用(APC)排队到I / O工作线程。如果应该在等待处于可警告状态的线程中执行,则应将工作项排队到I / O工作线程。

非I / O工作线程在I / O完成端口上等待。使用非I / O工作线程比使用I / O工作线程更有效。因此,您应尽可能使用非I / O工作线程。如果存在挂起的异步I / O请求,则I / O和非I / O工作线程都不会退出。两种类型的线程都可以由启动异步I / O完成请求的工作项使用。但是,如果可能需要很长时间才能完成,请避免在非I / O工作线程中发布异步I / O完成请求。

要使用线程池,它们调用的工作项和所有函数必须是线程池安全的。安全函数不假定执行它的线程是专用或持久线程。通常,应避免使用线程本地存储或进行需要持久线程的异步调用,例如RegNotifyChangeKeyValue函数。但是,可以在专用线程(由应用程序创建)或排队到持久工作线程(使用带有WT_EXECUTEINPERSISTENTTHREAD选项的QueueUserWorkItem)上调用此类函数。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值