前言

在我们日常生活中会遇到许许多多的问题,如果一个服务端要接受很多客户端的数据,该怎么办?多线程并发内存不够怎么办?所以我们需要了解线程池的相关知识。

一、线程池是什么?

1.线程池的简介

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动。

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:C/C++ ,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,点击立即学习

2.线程池的组成

1、线程池管理器(ThreadPoolManager):用于创建并管理线程池

2、工作线程(WorkThread): 线程池中线程

3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。

4、任务队列:用于存放没有处理的任务。提供一种缓冲机制。

3.线程池的主要优点

1.避免线程太多,使得内存耗尽

2.避免创建与销毁线程的代价

3.任务与执行分离

二、代码实现

1.线程池结构体定义

代码如下(示例):

struct nTask {void (*task_func)(struct nTask* task);void* user_data;struct nTask* prev;struct nTask* next;
};struct nWorker {pthread_t threadid;int terminate;struct nManager* manager;struct nWorker* prev;struct nWorker* next;
};typedef struct nManager {struct nTask* tasks;struct nWorker* workers;pthread_mutex_t mutex;//定义互斥锁pthread_cond_t cond;//条件变量
}ThreadPool;

2.接口定义

代码如下(示例):

//API
int nThreadPoolCreate(ThreadPool* pool, int numWorkers) {if (pool == NULL) return -1;if (numWorkers < 1) numWorkers = 1;memset(pool, 0, sizeof(ThreadPool));pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;memcpy(&pool->cond, &blank_cond, sizeof(pthread_cond_t));pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;memcpy(&pool->mutex, &blank_mutex, sizeof(pthread_mutex_t));int i = 0;for (i = 0; i < numWorkers; i++) {struct nWorker* worker = (struct nWorker*)malloc(sizeof(struct nWorker));if (worker == NULL) {perror("malloc");return -2;}memset(worker, 0, sizeof(struct nWorker));worker->manager = pool;int ret = pthread_create(&worker->threadid, NULL, nThreadPoolCallback, worker);if (ret) {perror("pthread_create");free(worker);return -3;}LIST_INSERT(worker, pool->workers);}return 0;
}//API
int nThreadPoolDestory(ThreadPool* pool, int nWorker) {struct nWorker* worker = NULL;for (worker = pool->workers; worker != NULL; worker = worker->next) {worker->terminate;}pthread_mutex_lock(&pool->mutex);pthread_cond_broadcast(&pool->cond);//唤醒所有线程pthread_mutex_unlock(&pool->mutex);pool->workers = NULL;pool->tasks = NULL;return 0;}//API
int nThreadPoolPushTask(ThreadPool* pool, struct nTask* task) {pthread_mutex_lock(&pool->mutex);LIST_INSERT(task, pool->tasks);pthread_cond_signal(&pool->cond);//唤醒一个线程pthread_mutex_unlock(&pool->mutex);}

3.回调函数

代码如下(示例):

static void* nThreadPoolCallback(void* arg) {struct nWorker* worker = (struct nWorker*)arg;while (1){pthread_mutex_lock(&worker->manager->mutex);while (worker->manager->tasks == NULL) {if (worker->terminate)break;pthread_cond_wait(&worker->manager->cond, &worker->manager->mutex);}if (worker->terminate) {pthread_mutex_unlock(&worker->manager->mutex);break;}struct nTask* task = worker->manager->tasks;LIST_REMOVE(task, worker->manager->tasks);pthread_mutex_unlock(&worker->manager->mutex);task->task_func(task);}free(worker);return;
}

4.全部代码(加注释)

代码如下(示例):

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>//Linux编程使用线程相关的就会用到这个,编译的时候还要加-lpthread,用pthread动态库#define LIST_INSERT(item,list) do{   \           //链表的增加item->prev = NULL;           \item->next = list;         \if((list)!=NULL)(list)->prev=item;    \(list) = item;                \
}while(0)#define LIST_REMOVE(item,list)do{  \           //链表的删除if (item->prev != NULL) item->prev->next = item->next; \if (item->next != NULL) item->next->prev = item->prev;   \if (item == list) list = item->next;                 \item->prev = item->next = NULL;                            \
}while(0)struct nTask {     //任务void (*task_func)(struct nTask* task);void* user_data;struct nTask* prev;struct nTask* next;
};struct nWorker {  //工作pthread_t threadid;int terminate;   //用来判断工作是否结束,以便于终止struct nManager* manager;  //可以用来查看任务struct nWorker* prev;struct nWorker* next;
};typedef struct nManager { //管理struct nTask* tasks;struct nWorker* workers;pthread_mutex_t mutex;//定义互斥锁,也可以用自旋锁pthread_cond_t cond;//条件变量
}ThreadPool;//callback!=task
static void* nThreadPoolCallback(void* arg) {struct nWorker* worker = (struct nWorker*)arg;    //接受pthread_create传来的参数while (1)    //默认一直执行{pthread_mutex_lock(&worker->manager->mutex);//加锁while (worker->manager->tasks == NULL) {if (worker->terminate)break;pthread_cond_wait(&worker->manager->cond, &worker->manager->mutex);//如果没有任务就等待}if (worker->terminate) {pthread_mutex_unlock(&worker->manager->mutex);//解锁break;}struct nTask* task = worker->manager->tasks;LIST_REMOVE(task, worker->manager->tasks);pthread_mutex_unlock(&worker->manager->mutex);task->task_func(task);}free(worker);return;
}//API
int nThreadPoolCreate(ThreadPool* pool, int numWorkers) {if (pool == NULL) return -1;if (numWorkers < 1) numWorkers = 1;//如果任务数量小于1,就默认为1memset(pool, 0, sizeof(ThreadPool));pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;//创建互斥量cond,静态全局memcpy(&pool->cond, &blank_cond, sizeof(pthread_cond_t));//pthread_mutex_init(&pool->mutex, NULL);pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;//创建互斥锁,静态全局memcpy(&pool->mutex, &blank_mutex, sizeof(pthread_mutex_t));int i = 0;for (i = 0; i < numWorkers; i++) {struct nWorker* worker = (struct nWorker*)malloc(sizeof(struct nWorker));if (worker == NULL) {perror("malloc");return -2;}memset(worker, 0, sizeof(struct nWorker));worker->manager = pool;int ret = pthread_create(&worker->threadid, NULL, nThreadPoolCallback, worker);if (ret) {perror("pthread_create");free(worker);return -3;}LIST_INSERT(worker, pool->workers);}return 0;
}//API
int nThreadPoolDestory(ThreadPool* pool, int nWorker) {struct nWorker* worker = NULL;for (worker = pool->workers; worker != NULL; worker = worker->next) {worker->terminate;}pthread_mutex_lock(&pool->mutex);pthread_cond_broadcast(&pool->cond);//唤醒所有线程pthread_mutex_unlock(&pool->mutex);pool->workers = NULL;//置空pool->tasks = NULL;//置空return 0;}//API
int nThreadPoolPushTask(ThreadPool* pool, struct nTask* task) {pthread_mutex_lock(&pool->mutex);LIST_INSERT(task, pool->tasks);pthread_cond_signal(&pool->cond);//唤醒一个线程pthread_mutex_unlock(&pool->mutex);}#if 1#define THREADPOOL_INIT_COUNT  20
#define TASK_INIT_SIZE          1000void task_entry(struct nTask* task) {int idx = *(int*)task->user_data;printf("idx: %d\n", idx);free(task->user_data);free(task);
}int main(void) {ThreadPool pool = { 0 };nThreadPoolCreate(&pool, THREADPOOL_INIT_COUNT);int i = 0;for (i = 0; i < TASK_INIT_SIZE; i++) {struct nTask* task = (struct nTask*)malloc(sizeof(struct nTask));if (task == NULL) {perror("malloc");exit(1);}memset(task, 0, sizeof(struct nTask));task->task_func = task_entry;task->user_data = malloc(sizeof(int));*(int*)task->user_data = i;nThreadPoolPushTask(&pool, task);}getchar();//防止主线程提前结束任务}#endif
总结

总结

关于线程池是基本代码就在上面了,关于编程这一部分内容,我建议大家还是要自己去动手实现,如果只是单纯的看了一遍,知识这块可能会记住,但是操作起来可能就比较吃力,万事开头难,只要坚持下去,总会有结果的。

参考资料

C/C++ Linux后台高级开发

内容包括C++工程化、高性能及分布式、深入浅出。性能调优、TCP,协程,Nginx源码分析Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,Linux内核,P2P,K8S,Docker,TCP/IP,协程,DPDK多个高级知识点。

以下视频学习资料获取点击:C++架构师学习资料

Linux环境,C/C++语言手写代码实现线程池相关推荐

  1. 高并发:线程、线程锁与线程池(精华),文中附上一个手写代码实现线程池视频(c/c++语言)

    前文: 单线程--多线程的开启--线程锁--线程同步工具--手写连接池--连接池工具类. 一.线程 1.线程的概念 2.线程与进程的关系 3.定义: 区别:如上!!! 4.wait()和sleep() ...

  2. python是如何实现进程池和线程池的_高并发:线程、线程锁与线程池(精华),手写代码实现线程池...

    前文: 单线程--多线程的开启--线程锁--线程同步工具--手写连接池--连接池工具类. 一.线程 1.线程的概念 2.线程与进程的关系 3.定义: 区别:如上!!! 4.wait()和sleep() ...

  3. 【线程池】自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协议丨C/C++Linux服务器开发

    [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码 视频讲解如下,点击观看: [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协 ...

  4. 【线程池】自行准备linux环境,带你手写线程池,只需仅仅150行代码

    [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码 视频讲解如下,点击观看: [线程池]自行准备linux环境,带你手写线程池,只需仅仅150行代码|内存池|API|连接池|应用协 ...

  5. 手写单例模式的线程池实践

    场景,有两个接口分别会接收两个数据,如果其中一个数据校验失败,那么另一个数据也要删掉. 由于是两个独立的数据源,没法做事务的回滚.( 这两个数据源是来自canal的监听得到的). 因此考虑的方案就是, ...

  6. c语言Linux用线程创建文件,Linux环境下C语言线程创建---简单代码

    在Linux环境下用C语言编写线程创建. //file name: pthreadtext.c #include #include //线程头文件 //pthread不是linux下的默认的库,也就是 ...

  7. linux环境c语言课程设计,linux环境下c语言编程课程设计

    linux环境下c语言编程课程设计 (14页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.90 积分 1/14LINUX操作系统教程课程设计题目算术 ...

  8. Linux环境下——C语言聊天室项目

    由于使用了多线程操作,客户端进入程序后请先随便注册一次用户后再进行使用. 本程序默认第一个用户即ID为1的用户为超级管理员. 由于线程阻塞,最后的踢人操作有阻塞,需要在被踢出在线链表后手动下线. 看了 ...

  9. C语言手写SDS字符串的实现思路

    C语言手写SDS字符串的实现思路 Simple Dynamic Strings (简称 SDS) 是一个 C 语言封装的的字符串,它增强了 C 语言字符串处理的能力. SDS 的 C 语言实现通常包括 ...

最新文章

  1. java string问题_Java关于String的问题?
  2. python高级语法-collections模块下几个新序列
  3. C语言 十进制整数字符串转十六进制字符串
  4. Linq动态查询与模糊查询
  5. 接触的第二个引擎 scaleform
  6. VC限制只能输入常规数字的CEdit控件
  7. 如何修复崩溃的WordPress数据库表
  8. 分布式数据库DDM Sidecar模式负载均衡
  9. Oracle中一把梭获取对象DDL创建语句
  10. Hadoop完全分布式集群——Hadoop 配置
  11. H3CSE园区-SSH
  12. python爬虫案例典型:爬取大学排名(亲测有效)
  13. 重庆大学计算机学院小学期安排,2019年重庆大学寒假放假时间安排是什么 重庆大学2019年学校校历如何安排...
  14. BF算法(Java实现)
  15. 用Keil uVision5创建纯汇编语言的STM32工程
  16. 如何做机器学习模型质量保障及模型效果评测
  17. 避免使用std::dynamic_pointer_cast
  18. html中字段间距代码,css调字体大小代码 css字与字之间的间距怎么调
  19. C# 将PPT的每一页保存为图片
  20. 万能数据库查询分析器使用技巧之(十)

热门文章

  1. revit导出lumion插件_【BIM前沿】Revit与Lumion的强强联合
  2. creo动画如何拖动主体_Creo如何制作关键帧动画?
  3. 山东大学暑期项目实训-基于信用评分卡算法模型的个人信用评级系统的设计与实现-第三周-9(7月16日)
  4. Unity 艺术字体
  5. 3个高效智能抠图工具,智能一键抠图,小白也能轻松搞定
  6. 如何轻松应对光纤传输容量不足?DWDM光模块实现链路扩容
  7. 本科生出来做机器学习,数据挖掘的工作会比研究生差很多吗?
  8. idea导入springboot项目运行教程
  9. 随机模拟三组来自相同或不同分布的随机数据,并计算他们的协方差矩阵,判断其正定性
  10. java 硬币_如何将一笔钱兑换成纸币和硬币