池
池是一组资源的集合,这组资源在服务器启动之初就被创建和初始化,这称为静态资源分配。它避免了服务器对内核的频繁访问,提高了效率。
常见的池有进程池,线程池,内存池
内存池
先申请一定数量,大小相等的内存块备用。有新的内存需求时,就从内存池中分出一部分内存块,若内存不足则继续申请新的内存。内存池使内存分配效率得到提升
进程池
进程池线先由服务器创建一组子进程,子进程数量应和CPU数量差不多。所有子程序具有相同的属性,运行着同样的代码
线程池
概念
在Linux中线程实际上是由轻量级进程实现的。线程的创建和清理都需要耗费时间和系统资源,当处理高并发时,线程池就有必要引入了。
线程池提升了多线程程序的性能,因为线程池中线程都是现成且可重复使用的。理想的线程池能够合理地动态调节池内线程数量
线程池是典型的生产者消费者同步问题,主程序不定时将任务任务添加到一个队列中。池中多个工作线程同时执行出队操作(需保证同一时刻只能一个线程出队成功)。这时候生产者是主程序(用于生产任务),消费者是工作线程(用于执行任务)
组成结构
线程池主要包括4个部分:
- 线程管理器:用于创建并管理线程池
- 工作线程:线程池中实际执行任务的线程,在创建线程池后会创建好固定数目的线程在池中
- 任务接口:每个任务必须实现的接口。当队列中有任务时,被池中线程执行,把任务抽象成一个接口,可以做到线程池与具体任务无关
- 任务队列:用于存放没有处理的任务
应用
主要应用于需要大量线程来完成任务且任务时间较短,例如Web服务器完成网页请求。或者是突发性的大量请求
代码实现
test.h文件:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
//任务接口(节点)
struct Work {
void* (*func) (void *arg);
void *arg;
Work *next;
};
//线程池中线程执行的回掉函数
void* thread_poll_func(void *arg);
//线程池
struct thread_poll{
//任务队列
Work *head;
//线程指针
pthread_t *pd;
//条件变量和锁
pthread_mutex_t mutex;
pthread_cond_t cond;
//线程池是否被销毁
bool shutdown;
//线程池中线程的总量
int pthread_num;
//当前任务队列中任务数量
int work_num;
//初始化函数
thread_poll(int pthread_num) {
this -> pthread_num = pthread_num;
this -> work_num = 0;
this -> shutdown = 0;
pthread_mutex_init(&this ->mutex, NULL);
pthread_cond_init(&this -> cond, NULL);
this -> head = NULL;
pd = (pthread_t *)malloc(sizeof(pthread_t) * pthread_num);
for (int i = 0; i < pthread_num; i++) {
pthread_create(&this -> pd[i], NULL, thread_poll_func, this);
}
}
//向线程池投递任务
void add_work(Work *work);
//销毁线程池
int del();
};
test.cpp文件:
#include "test.h"
//线程池中线程执行的回掉函数
void* thread_poll_func(void *arg) {
thread_poll *t = (thread_poll *)arg;
while(1) {
//上锁
pthread_mutex_lock(&t -> mutex);
//循环等待接收任务
while(!(t -> work_num) && !(t -> shutdown)) {
pthread_cond_wait(&t -> cond, &t -> mutex);
}
//如果线程池被销毁
if (t -> shutdown) {
//解锁并退出线程
pthread_mutex_unlock(&t -> mutex);
pthread_exit(0);
}
//取出队首任务
t -> work_num --;
Work *p = t -> head;
t -> head = p -> next;
//解锁
pthread_mutex_unlock(&t -> mutex);
//执行任务回掉函数
(p -> func)(p -> arg);
//释放该任务空间
free(p);
}
}
//向线程池投递任务
void thread_poll::add_work(Work *work) {
pthread_mutex_lock(&this -> mutex);
//将任务加入到等待队列
Work *p = this -> head;
if (p == NULL) {
this -> head = work;
} else {
while(p -> next != NULL) {
p = p -> next;
}
p -> next = work;
}
this -> work_num ++;
pthread_mutex_unlock(&this -> mutex);
//唤醒一个等待线程
pthread_cond_signal(&this -> cond);
}
//销毁线程池
int thread_poll::del() {
if (this -> shutdown) {
return -1;
}
this -> shutdown = 1;
//唤醒所有线程
pthread_cond_broadcast(&this -> cond);
//等待所有线程结束,避免僵尸线程
for (int i = 0; i < this -> pthread_num; i++) {
pthread_join(this -> pd[i], NULL);
}
//释放掉所有线程标识符
free(pd);
//销毁任务队列的所有任务
Work *p = this -> head;
while(p != NULL) {
p = this -> head;
this -> head = p -> next;
free(p);
}
//销毁条件变量和锁
pthread_cond_destroy(&this -> cond);
pthread_mutex_destroy(&this -> mutex);
return 0;
}
//任务的回掉函数
void* myfunc(void *arg) {
printf("%d\n", *(int *)arg);
return NULL;
}
int main () {
thread_poll poll(3);
int *nuu = (int *)malloc(sizeof(int) * 10);
for (int i = 0; i < 10; i++) {
nuu[i] = i;
Work *work = (Work *)malloc(sizeof(Work));
work -> next = NULL;
work -> func = myfunc;
work -> arg = (void *)&nuu[i];
poll.add_work(work);
}
sleep(5);
poll.del();
free(nuu);
return 0;
}
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢