完成端口之二:线程池部分

一、线程池的基本原理
在传统服务器架构中, 常常是有一个总的监听线程监听有没有新的用户连接服务器, 每当有一个新的用户连接进入, 服务器端就开启一个新的线程去处理这个用户的请求,与其进行数据的收发。
这个线程只服务于这个用户, 当用户与服务器端关闭连接以后, 服务器端才销毁这个线程。然而频繁地开辟与销毁线程极大地占用了系统的资源。而且在大量用户的情况下, 少则1000,多则上万,系统为了开辟和销毁线程将浪费大量的时间和资源。

线程池技术很好的解决了这个问题,它的基本思想就是在程序开始时就在内存中开辟一些线程, 当有新的客户请求到达时,
不是新创建一个线程为其服务, 而是从“池子”中选择一个空闲的线程为新的客户请求服务,服务完毕后,线程不是退出,而是进入空闲线程池中。

通过对多个任务重用已经存在的线程对象, 降低了对线程对象创建和销毁的开销。当客户请求时, 线程对象已经存在, 可以提高请求的响应时间, 从而整体地提高了系统服务的表现。

二、线程池的实现

本示例中采用微软自带的线程池API

三、使用注意事项:

使用线程池用到的最重要的 Windows API 函数:QueueUserWorkItem,其定义如下:
BOOL WINAPI QueueUserWorkItem(
__in LPTHREAD_START_ROUTINE Function,
__in PVOID Context,
__in ULONG Flags
);

● 参数 Function 是一个函数指针,指向线程池中的线程必须要完成的工作,该函数必须具有以下形式:
DWORD WINAPI Function(LPVOID lpParam);
大家可以发现,这个函数跟创建线程的线程函数拥有相同的形式;

● 参数 Context 是一个 void 类型的指针,与传递给线程函数的 lpParam 是一个值;

● 参数 Flags 在下面介绍。

当第一次调用 QueueUserWorkItem 时, Windows操作系统将创建一个线程池,其中的一个线程将执行 Function 函数,函数执行完成后,该线程返回线程池,等待新的任务。
由于 Windows 依赖于该过程来完成线程池的功能,因此 Function 中不能有任何中止该线程的调用,如 ExitThread。
假如当调用 QueueUserWorkItem 时,没有可用的线程,Windows 就可以通过创建额外的线程增加线程池中线程的数量。
线程池中的线程的数量是动态的,并且受 Windows 的控制,Windows 内部的调度算法决定处理当前线程工作负载的最佳方式。

如果知道所要处理的工作需要很长时间才能完成,可以在调用 QueueUserWorkItem 时,将参数的 Flags 设置为 WT_EXECUTELONGFUNCTION ,
这时如果线程池中的所有的线程都处于忙状态, 那么 Windows 将自动创建新的线程。

Windows 线程池中的线程有两种类型,一种可以用来处理异步I/O,另一种则不能。
前者依赖于IO完成端口,IOCP是一种Windows内核对象,它可以将线程和 I/O 端口绑定在特定的系统资源上,对带有完成端口的 I/O 进行处理是一个复杂的过程。

调用 QueueUserWorkItem 时,需要标识哪些线程执行 I/O,哪些线程不执行 I/O, 将 QueueUserWorkItem 中的 Flags 设置成 WT_EXECUTIONDEFAULT,
就可以告诉线程池该线程不执行异步 I/O,从而可以对其进行相应的管理;对于执行异步 I/O 的线程,则应该将其 Flags 设置为 WT_EXECUTEIONIOTHREAD.

111
原文地址:https://www.cnblogs.com/zwj-199306231519/p/13946611.html