目录
2、pthreadpool.h (pthreadpool.h 代码)
本部分主要整理 “ Web 服务器 ” 项目线程池类以及其中遇到的一些典型问题
1、线程池
线程池是由服务器预先创建的一组子线程,线程池中的线程数量应该和 CPU 数量差不多。线程池中的所有子线程都运行着相同的代码。当有新的任务到来时,主线程将通过某种方式选择线程池中的某一个子线程来为之服务。相比与动态的创建子线程,选择一个已经存在的子线程的代价显然要小得多。
线程池的一般模型如下:
线程池中的线程数量最直接的限制因素是中央处理器 (CPU) 的处理器 (processors/cores) 的数量 N:如果你的 CPU 是 4-cores 的,对于 CPU 密集型的任务 (如视频剪辑等消耗 CPU 计算资源的任务) 来说,那线程池中的线程数量最好也设置为 4(或者+1防止其他因素造成的线程阻塞);对于 IO 密集型的任务 (如 Web 服务器),一般要多于 CPU 的核数,因为线程间竞争的不是 CPU 的计算资源而是 IO,IO 的处理一般较慢,多于 cores 数的线程将为 CPU 争取更多的任务,不至在线程处理 IO 的过程造成 CPU 空闲导致资源浪费。
- 空间换时间,浪费服务器的硬件资源,换取运行效率
- 池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源
- 当服务器进入正式运行阶段,开始处理客户请求的时候,如果它需要相关的资源,可以直接从池中获取,无需动态分配
- 当服务器处理完一个客户连接后,可以把相关的资源放回池中,无需执行系统调用释放资源
2、线程池工作原理
线程池是一种多线程处理形式,处理过程中将任务添加到工作队列,然后创建工作线程后自动启动这些任务。
线程池的代码实现:线程池主要包括工作队列和线程池。在创建线程池类时,利用构造函数创建多个工作线程,这些线程在创建时就规定了需要处理的逻辑代码 worker() ,即从工作队列中取出任务,交给 process() 函数处理。之后在线程池类中定义一个 append() 函数,用于向工作队列中添加任务。如下图所示
注:这些工作线程自创建后一直在执行 worker() 函数,只要 append() 函数向工作队列中添加任务(或者只要工作队列不为空),那么工作线程就会从工作队列中取出任务,进行处理。
附录
1、locker.h
(locker.h)
2、pthreadpool.h
-
线程池中的工作队列会被所有线程共享,所以要考虑线程同步问题,所以 locker.h 出现了;
-
int a[10] 和 int* a=new int[10] 的区别(链接)
-
pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); 中的 start_routine 函数,在 C 中是一个全局函数,在 C++ 中是一个静态函数;
-
将线程设置为分离 pthread_detach() ,是为了让线程运行结束后自动释放所有资源;
-
函数形参列表中 void * arg:
void 的字面意思是“ 无类型 ”,void * 则为“ 无类型指针 ”,void * 可以指向任何类型的数据。
-
worker 是一个静态函数,而 worker 会用到类里的一些成员。而这些成员不是静态的,所以使用 this 作为本类对象传递给 worker