linux高性能服务器-线程池实现

文章目录

        • 定义
        • 应用场景
        • 任务类型
        • 线程数量
        • 数据结构设计:
          • 任务设计:
          • 队列设计:
          • 线程池设计
        • 接口设计

定义

线程池属于生产消费模型,管理维持固定数量线程的池式结构,避免线程频繁的创建和销毁

应用场景

当一类任务耗时,严重影响当前线程处理其他任务,异步执行

任务类型

耗时任务:

  • CPU密集型
  • IO密集型 ( 网络IO 磁盘IO)
线程数量

n * proc

数据结构设计:
任务设计:
typedef struct task_s {
	void * next;
	handler_pt func;
	void * arg;
} task_t;

生产者线程: 发布任务
消费者线程: 取出任务,执行任务
数据结构为链表

队列设计:

typedef struct task_queue_s {
	void * head;
	void **tail;
	int block; // 是否阻塞 
	spinlock_t lock; // 自选锁
	pthread_muxtex_t mutex;
	pthread_cond_t cond;
}task_queue_t;

队列: 存储任务,调度线程池 ,双端开口,先进先出,在多线程中执行,需要加锁
功能: 调取线程池中的消费者线程, 如果此时队列为空,谁(线程)来取任务,谁阻塞休眠
当允许一个进程进入临界资源(互斥状态)。
自旋锁: 其他线程空转cpu,一直等待进入临界资源
互斥锁:切换cpu, 让出执行权, 线程阻塞住,操作系统调用其他的线程

某个线程持有临界资源的时间 < 线程切换的时间 , 自旋锁 ,时间复杂度为0(1)
生产者新增任务,消费者取出任务 ,0(1),均为移动指针完成(尾插法,头插法)
故使用自旋锁 spinlock_t lock

线程池设计
struct thredpool_t {
	atomic_int quit;  // 原子变量
	int thrd_count;
	pthread_t * threads;
	task_queue_t task_queue;
};

原子操作:一个线程在执行过程中,其他线程不能执行这个线程的内部操作,只能看到线程执行前或者执行后
应用场景: 某一个基础类型给的变量

接口设计
static task_queue_t * __taksqueue_create() {
	task_queue_t  * queue = malloc(sizeof(*queue));
	int ret;
	ret = pthrad_mutex_init(&mutex);
	if(ret == 0) {
		ret = pthread_cond_init(&cond);
		if(ret == 0) {
			queue->head = NULL;
			queue->tail = &(queue->head);
			queue->block = 1;
			return queue;
		}
		pthread_cond_destory(&queue);
	}
	pthread_muext_destory(&queue->mutex);
	return NULL;
}

static void __add_task(task_queue_t  * queue, void * task) {
	void **link = (void **)task; // malloc
	*link = NULL; // task->next = NULL;
	spinlock_lock(&queue->lock);
	*queue->tail = link; // 末尾添加新的节点
	queue->tail = link // tail 指向新的尾节点
	spinlock_unlock(&qeuue->lock);
	pthread_cond_signal(&queue->cond); // 有任务,唤醒休眠的线程
}

static task_t * __pop__task(task_queue_t * queue) {
	spinlock_lock(&queue->lock);
	if(queue->head) {
		spinlock_unclock(&queue->lock);
		return NULL;
	}
	task_t *task;
	task = queue->head;
	queue->head = task->next;
	if(queue-head == NULL) {
		queue->tail = &queue->head; // &NULL
	}
	spinlock_unlock(&queue->lock);
	return task;
} 

static void * __get_task (task_queue_t *queue) {
	task_t *task;
	while((task = __pop_task(queue))== NULL) {
		pthread_mutex_lock(&queue->lock);
		if(queue->block == 0) {
			rerurn NULL;
		}
		// pthread_cond_wait 执行过程:
		// 1. 先unlock(&mutex)
		// 2. cond 休眠
		// 3, 生产者 发送signal
		// 4. cond 唤醒
		// 5. 既然上clock(&mutex)
		pthead_cond_wait(&queue->cond,&queue->mutex);  //休眠
		pthread_mutex_unlock(&queue->mutex);
	} 
	return task;
}

static void __taskqueue_destroy(task_queue_t * queue) {
	 task_t *task;
	 while((task) = _pop_task(queue)) {
	 	free(ptr:task);
	 }
	 spinlock_destroy(&queue->lock);
	 pthread_cond_destory(&queue->cond);
	 pthread_mutex_destory(&queue->mutex);
	 free(ptr:queue);
}

// 消费者线程 ,取出任务,执行任务
static void * __thrdpoll_worker(void *arg) {
	thrdpool_t *pool = (thrdpool *)arg;
	task_t *task;
	void *ctx;
	while(atomic_load(&pool->quit) == 0) {  //原子读
		task = (task *) __get_task(poll->task_queue);
		if(!task) {
			break;
		}
		handler_pt func = task->func;
		ctx = taks->arg;
		free(task);
		func(ctx);
	}
	return NULL;
}
// 设置队列为非阻塞,并唤醒所有的线程
static void __nonblock(task_queue_t *queue) {
	pthread->mutex_lock =&queue->lock;
	queue->block = 0;
	pthread_mutex_unclock(&queue->mutex);
	pthread_cond_broadcast(queue->cond); 
}
// 创建线程,回滚式创建对象
static int __threads_create(thrdpool * pool, size_t thrd_count) {
	pthread_attr_t attr;
	int ret;
	ret = pthread_attr_init(&attr); //初始化线程参数
	if (ret == 0) {
		pool_>threads = (pthread_t *)malloc(sizeof(pthread_t) * thrd_count);
		if(pool_threads) {
			int i = 0;
			for(;i < thrd_count; i++) {
				if(pthread_create(&pool->threads[i),&attr,start_routine(),NULL);
					break; // 创建线程失败,返回
			}
			pool->thrd_count  = i; 
			pthread_attr_destory(&attr);
			if( i == thrd_count)
				reurn 0;
			__threads_terminante(pool); // 如果创建的线程数量不等于thrd_count,把创建的线程全部销毁
			free(pool->threads); // 释放堆空间
		}
	}
	return ret;
}

// 创建线程池
static thrdpool_t *  thrdpool_create(int thrd_count) {
	thrdpool_t * pool;
	poll = (thrdpool_t *)malloc(sizeof(poll);
	if(!pool) return NULL;
	task_queue_t  *queue = __taskqueue_create();
	if(queue) {
		pool->task_queue = queue;
		atomic_init(&pool->quit, 0);
		if(__threads_create(pool,thrd_count) == 0 ) {
			return pool;
		}
		__taskqueue_destory(pool->taks_queue);
	}
	free(pool);
	return NULL;
}

static void __threads_terminate(thrdpool_t * pool) {
	atomic_store(&queue->quit,1); //原子写
	__nonblock(pool->task_queue); // 设置非阻塞队列,唤醒所有的线程
	int i;
	for(i=0; i<pool->thrd_count;i++) {
		pthread_join(pool->thread[i],NULL);
	}
}

// 生产者创建任务
static int thrdpool_post(thrdpool_t  * pool, handler_pt func, void *arg) {
	if (atomic_load(&pool->quit) == 1 ) {  //判断线程池是否标记退出
		return -1;
	}
	task * task = (task_t *)malloc(sizeof(task_t));
	if(!task)  return -1;
	task->func = func; // 初始化
	task->arg = arg;
	__add_task(pool->task_queue,task); // 添加任务
	return 0;
}

//等待所有线程结束,释放资源
static thrdpool_wait(thrdpool_t *pool) {
	int i;
	for(i=0; i<poll->thrd_count;i++) {
		pthread_join(pool->thread[i],NULL);
	}
	__taskqueue_destory(pool->taks_queue);
	free(pool->threads);
	free(pool);
}








本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/596286.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DS二叉搜索树

前言 我们在数据结构初阶专栏已经对二叉树进行了介绍并用C语言做了实现&#xff0c;但是当时没有对二叉搜树进行介绍&#xff0c;而是把他放到数据结构进阶构专栏的第一期来介绍&#xff0c;原因是后面的map和set&#xff08;红黑树&#xff09;是基于搜索树的&#xff0c;这里…

Java-(乘法表之后)增强for循环

这里我们先做个了解&#xff0c;之后我会在数组中进行详细介绍Java5引入了一种主要用于数组或集合的增强型for循环Java增强型for循环语法格式如下 For(声明语句&#xff1a;表达式&#xff09;{ //代码语句 } 声明语句&#xff1a;声明新的局部变量&#xff0c;该变量的类型…

Windows中安装的PostgreSQL 数据库如何重启

1. 使用Windows服务管理器 打开“运行”对话框&#xff08;按WinR键&#xff09;。输入services.msc并按回车&#xff0c;这将打开服务列表。在服务列表中找到PostgreSQL服务。它通常命名为“PostgreSQL”后面跟着版本号和实例名称&#xff0c;例如“PostgreSQL 13 - mydb”。…

【云原生】Pod 的生命周期(一)

【云原生】Pod 的生命周期&#xff08;一&#xff09;【云原生】Pod 的生命周期&#xff08;二&#xff09; Pod 的生命周期&#xff08;一&#xff09; 1.Pod 生命期2.Pod 阶段3.容器状态3.1 Waiting &#xff08;等待&#xff09;3.2 Running&#xff08;运行中&#xff09;3…

后缀表达式

什么是后缀表达式&#xff1f; 在计算机科学和数学领域&#xff0c;表达式求值是一项基本且频繁的任务。我们熟知的中缀表达式&#xff08;如 7 15 ∗ 1 4 ∗ 1&#xff09;直观易读&#xff0c;但在计算机处理时却需要复杂的栈或递归算法来解析。相比之下&#xff0c;后缀表…

深度学习中的优化算法:选择现有的还是自创?

深度学习中的优化算法 深度学习中的优化算法&#xff1a;选择现有的还是自创&#xff1f;现有优化算法的优势**优点包括**&#xff1a; 开发新的优化算法的考虑**开发新算法的原因**&#xff1a;**开发新算法的风险**&#xff1a; 实用建议结论 深度学习中的优化算法&#xff1…

RabbitMQ 是如何做延迟消息的 ?——Java全栈知识(15)

RabbitMQ 是如何做延迟消息的 &#xff1f; 1、什么是死信&#xff1f; 当一个队列中的消息满足下列情况之一时&#xff0c;可以成为死信&#xff08;dead letter&#xff09;&#xff1a; 消费者使用 basic.reject 或 basic.nack 声明消费失败&#xff0c;并且消息的 reque…

5-在Linux上部署各类软件

1. MySQL 数据库安装部署 1.1 MySQL 5.7 版本在 CentOS 系统安装 注意&#xff1a;安装操作需要 root 权限 MySQL 的安装我们可以通过前面学习的 yum 命令进行。 1.1.1 安装 配置 yum 仓库 # 更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022# 安装Mysql…

rk3588局域网推流

最近无意间看见在网上有使用MediaMtx插件配合ffmpeg在Windows来进行推流&#xff0c;然后在使用其他软件进行拉流显示数据图像的&#xff0c;既然windows都可以使用 &#xff0c;我想linux应该也可以&#xff0c;正好手上也有一块RK3588的开发板&#xff0c;就测试了一下&#…

iOS ------ JSONModel源码

一&#xff0c;JSONModel的基本使用 1&#xff0c;基本使用方法 - (instancetype)initWithDictionary:(NSDictionary *)dict error:(NSError **)err; - (instancetype)initWithData:(NSData *)data error:(NSError **)error; - (instancetype)initWithString:(NSString *)str…

Linux网络-部署YUM仓库及NFS共享服务

目录 一.YUM仓库服务 1.YUM概述 1.1.YUM&#xff08;Yellow dog Updater Modified&#xff09; 2.准备安装源 2.1.软件仓库的提供方式 2.2.RPM软件包的来源 2.3.构建CentOS 7 软件仓库 2.4.在软件仓库中加入非官方RPM包组 3.一键安装软件包的工具&#xff1a; 好处&a…

申请Sectigo证书流程详解

Sectigo&#xff08;前身为Comodo CA&#xff09;&#xff0c;是目前主流SSL证书的一种&#xff0c;目前全球范围内应用度也非常广泛&#xff0c;是目前众多品牌中市场份额最大的一个品牌了&#xff0c;在全球证书市场份额占比约为40%。 其超高的市场份额占比主要还是基于其超…

021、Python+fastapi,第一个Python项目走向第21步:ubuntu 24.04 docker 安装mysql8集群、redis集群(二)

系列文章目录 pythonvue3fastapiai 学习_浪淘沙jkp的博客-CSDN博客https://blog.csdn.net/jiangkp/category_12623996.html 前言 安装redis 我会以三种方式安装&#xff0c;在5月4号修改完成 第一、直接最简单安装&#xff0c;适用于测试环境玩玩 第二、conf配置安装 第三…

【Leetcode 42】 接雨水

基础思路&#xff1a; &#xff08;1&#xff09;需要将问题最小化&#xff0c;首先计算第i个位置最多容纳多少雨水&#xff08;细长的一条水柱&#xff09;&#xff0c;然后求和就是总的雨水量&#xff1b; &#xff08;2&#xff09;第i个位置容纳雨水量 min(左侧最高, 右…

​《MATLAB科研绘图与学术图表绘制从入门到精通》示例:绘制德国每日风能和太阳能产量3D线图

在MATLAB中&#xff0c;要绘制3D线图&#xff0c;可以使用 plot3 函数。 在《MATLAB科研绘图与学术图表绘制从入门到精通》书中通过绘制德国每日风能和太阳能产量3D线图解释了如何在MATLAB中绘制3D线图。 购书地址&#xff1a;https://item.jd.com/14102657.html

牛客热题:单链表排序

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;单链表排序题目链接方法一&…

【XR806开发板试用】基于MQTT与Cjson库的花式点灯

一、项目介绍 久闻openharmony大名&#xff0c;一直没有机会接触&#xff0c;感谢极术社区和全志社区的这次活动&#xff0c;让我能够了解并上手这个系统。 openhamony 1.1的内核是基于liteos内核系统进行构建的&#xff0c;liteos作为物联网系统&#xff0c;结合xr806小型开…

美团KV存储squirrel和Celler学习

文章目录 美团在KV存储squirrel优化和改进在水平方向1、对Gossip协议进行优化 在垂直扩展方面1、forkless RDB数据复制优化2、使用多线程&#xff0c;充分利用机器的多核能力 在高可用方面 美团持久化kv存储celler优化和改进水平扩展优化1、使用bulkload进行数据导入2、线程模型…

Adobe系列软件安装

双击解压 先运行Creative_Cloud_Set_Up.exe。 完毕后&#xff0c;运行AdobeGenP.exe 先Path&#xff0c;选路径&#xff0c;如 C:\Program Files\Adobe 后Search 最后Patch。 关闭软件&#xff0c;修图&#xff01;

电力能源箱3D可视化:开启智慧能源管理新篇章

随着科技的不断进步&#xff0c;电力能源箱的管理与维护逐渐向着智能化、可视化的方向发展。3D可视化技术的崛起&#xff0c;不仅极大地提升了能源管理的效率&#xff0c;更以其直观、生动的特点&#xff0c;引领着电力能源管理领域迈入了一个全新的时代。 电力能源箱作为电力系…
最新文章