news 2026/4/21 14:39:17

线程池原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
线程池原理

线程池的使用场景:

服务器连接通信

  • 在服务器与客户端建立连接进行通信的时候,需要用到多线程进行,如果客户端有10万个,则按照普通做法,即一客户端一线程,需要开10万个线程,而在posix标准的线程,一个有8M,则16G内存只有2048个线程可开,故引出了线程池。

日志文件

  • 磁盘操作远远比内存操作慢很多,在写线程的时候,会引起线程的挂起。故在落盘即执行写操作时与如何写,
    这两个问题分开,如何写即是任务,执行写操作即是执行。

线程池的好处:

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

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

  3. 任务与执行分离。

线程池的基本原理:

一个任务队列与一个执行队列,中间一个管理组件。

管理组件中有这两个队列与一个mutex锁,其中还有一个条件变量,这个条件变量的作用是

来使执行队列进行。

线程池即可以理解为上图中的管理组件。

故线程池需要定义三个东西,定义如下:

1.任务队列

structnTask{/* data */void(*task_func)(structnTask*task);void*user_data;structnTask*prev;structnTask*next;};

2. 执行队列

structnWorker{pthread_t thread_id;intterminate;structnManager*manager;structnWorker*prev;structnWorker*next;};

3.管理模块

typedefstructnManager{structnTask*tasks;structnWorker*workers;pthread_mutex_t mutex;pthread_cond_t cond;}ThreadPool;

API定义

所需要提供给用户的API主要有以下功能,创建一个线程池,销毁一个线程池,往线程池里添加任务。

1. 创建线程池

这里面做两件事情,一个是激活执行队列中的“工人”,二是去任务队列里取任务。

intnThreadPoolCreate(ThreadPool*pool,intnumWorkers){//创建线程池,首先初始化各个参数if(pool==NULL)return-1;//工人必须大于等于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_init(&pool->mutex,NULL);inti=0;for(i=0;i<numWorkers;i++){structnWorker*worker=(structnWorker*)malloc(sizeof(structnWorker));if(worker==NULL){perror("malloc");return-2;}memset(worker,0,sizeof(structnWorker));worker->manager=pool;// INFO("nthreadpool worker %d start\n",i);intret=pthread_create(&worker->thread_id,NULL,nThreadPoolCallback,worker);if(ret){perror("pthread_create");free(worker);return-3;}LIST_INSERT(worker,pool->workers);}return0;}

其中LIST_INSERT是通过宏定义的函数,即链表的插入操作:

#defineLIST_INSERT(item,list)do{\item->prev=NULL;\item->next=list;\if((list)!=NULL)(list)->prev=item;\list=item;\}while(0)

2.线程回调函数

staticvoid*nThreadPoolCallback(void*arg){structnWorker*worker=(structnWorker*)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;}//有任务就取出任务structnTask*task=worker->manager->tasks;//从头取出一个节点LIST_REMOVE(task,worker->manager->tasks);pthread_mutex_unlock(&worker->manager->mutex);task->task_func(task);}free(worker);}

这其中的LIST_REMOVE也是通过宏定义的函数,即链表的删除操作:

#defineLIST_REMOVE(item,list)do{\if(item->prev!=NULL)item->prev->next=item->next;\if(item->next!=NULL)item->next->prev=item->prev;\if(list==item)list=item->next;\item->prev=item->next=NULL;\}while(0)

3.销毁线程池

其中要做的就是切断work结构体与task结构体的联系,并将线程回调函数终止。

intnThreadPoolDestory(ThreadPool*pool,intnWorker){structnWorker*worker=NULL;for(worker=pool->workers;worker!=NULL;worker=worker->next){worker->terminate=1;}//这里加锁的原因是防止在广播时有些还未进行wait的即将进行wait的条件都一起满足!!!!pthread_mutex_lock(&pool->mutex);//唤醒所有线程,叫醒正在睡觉的员工,叫他们下班。pthread_cond_broadcast(&pool->cond);pthread_mutex_unlock(&pool->mutex);pool->workers=NULL;pool->tasks=NULL;}

4.向线程池中添加任务

intnThreadPoolPushTask(ThreadPool*pool,structnTask*task){pthread_mutex_lock(&pool->mutex);LIST_INSERT(task,pool->tasks);//唤醒一个线程pthread_cond_signal(&pool->cond);pthread_mutex_unlock(&pool->mutex);}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 14:38:31

ThinkPad风扇控制终极指南:TPFanCtrl2完整教程与性能优化

ThinkPad风扇控制终极指南&#xff1a;TPFanCtrl2完整教程与性能优化 【免费下载链接】TPFanCtrl2 ThinkPad Fan Control 2 (Dual Fan) for Windows 10 and 11 项目地址: https://gitcode.com/gh_mirrors/tp/TPFanCtrl2 ThinkPad风扇控制软件TPFanCtrl2是一款专为ThinkP…

作者头像 李华
网站建设 2026/4/21 14:36:40

苹果权力交接:库克卸任,特尔努斯2026年接棒CEO,斯鲁吉任首席硬件官

库克卸任&#xff0c;特尔努斯接棒苹果CEO苹果公司首席执行官蒂姆库克即将卸任&#xff0c;现任苹果硬件工程高级副总裁的约翰特尔努斯将于2026年9月1日正式接任这一职位&#xff0c;并加入苹果董事会。库克于1998年加入苹果&#xff0c;2011年从史蒂夫乔布斯手中接过首席执行官…

作者头像 李华