day10 线程池及gdb调试多线程

news2024/10/7 8:24:25

目录

线程池的概念

概念:

必要性:

线程池的基本结构:

线程池的实现

 完整代码

线程的GDB调试


线程池的概念

概念:

通俗的讲就是一个线程的池子,可以循环的完成任务的一组线程集合;

必要性:

我们平时创建一个线程,完成某一个任务,等待线程的退出。但当需要创建大量的线程时;

假设T1为创建线程时间,T2为在线程任务执行时间,T3为线程销毁时间;

当T1 + T3 > T2,这时候就不划算了,使用线程池可以降低频繁创建和销毁线程所带来的的凯西欧啊,任务处理时间比较短的时候这个好处非常显著。

线程池的基本结构:

1、任务队列,存储需要处理的任务,由工作线程来处理这些任务;

2、线程池工作线程,他是任务队列任务的消费者,等待新任务的信号;

线程池的实现

1、创建线程池的基本结构:

typedef struct Task;         //任务队列链表
typedef struct ThreadPool;   //线程池结构体

2、线程池的初始化:

pool_init() {
        创建一个线程池结构;
        实现任务队列互斥锁和条件变量的初始化;
        创建n个工作线程;
}

 使用互斥锁是因为,任务队列链表是一个临界资源;

3、线程池添加任务:

pool_add_task {
        判断是否有空闲的工作线程;
        给任务队列添加一个节点;
        给工作线程发送信号newtask
}

4、实现工作线程:

workThread {
        while(1) {
            等待newtask任务信号;
            从任务队列中删除节点;
            执行任务;
        }
}

5、线程池的销毁:

pool_destory {
        删除任务队列链表的所有节点,释放空间;
        删除所有的互斥锁条件变量;
        删除线程池,释放空间;
}

 完整代码

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>

#define POOL_NUM 10

//任务队列链表结构体;
typedef struct Task{
	void *(*func)(void *arg);
	void *arg;
	struct Task *next;
}Task;


//线程池结构体;
typedef struct ThreadPool {
	pthread_mutex_t taskLock;
	pthread_cond_t newTask;

	pthread_t tid[POOL_NUM];
	Task *queue_head;
	int busywork;
}ThreadPool;

//线程池变量;
ThreadPool *pool;

//实现工作线程;
void *workThread(void *arg) {
	while (1) {
		pthread_mutex_lock(&pool->taskLock);
		pthread_cond_wait(&pool->newTask, &pool->taskLock);

		Task *ptask = pool->queue_head;
		pool->queue_head = pool->queue_head->next;

		pthread_mutex_unlock(&pool->taskLock);

		ptask->func(ptask->arg);
		pool->busywork--;
	}
}

//被执行的工作内容
void *realwork(void *arg) {
	printf("finish work %d\n", (int)arg);
}

//线程池添加任务;
void pool_add_task(int arg) {
	//判断
	Task *newTask;
	pthread_mutex_lock(&pool->taskLock);
	while(pool->busywork >= POOL_NUM) {
		pthread_mutex_unlock(&pool->taskLock);
		usleep(10000);
		pthread_mutex_lock(&pool->taskLock);
	}
	pthread_mutex_unlock(&pool->taskLock);

	//创建一个新任务
	newTask = malloc(sizeof(Task));
	newTask->func = realwork;
	newTask->arg = arg;

	//将新任务添加到任务队列;
	pthread_mutex_lock(&pool->taskLock);
	
	Task *member = pool->queue_head;
	if (member == NULL) {
		pool->queue_head = newTask;
	}else{
		while(member->next != NULL) {
			member = member->next;
		}
		member->next = newTask;
	}

	pool->busywork++;
	pthread_cond_signal(&pool->newTask);
	
	pthread_mutex_unlock(&pool->taskLock);
}


//线程池初始化;
void pool_init(){
	pool = malloc(sizeof(ThreadPool));
	pthread_mutex_init(&pool->taskLock, NULL);
	pthread_cond_init(&pool->newTask, NULL);
	pool->queue_head = NULL;
	pool->busywork = 0;

	//创建n个工作线程
	int i;
	for(i = 0; i < POOL_NUM; i++){
		pthread_create(&pool->tid[i], NULL, workThread, NULL);
	}
}

//线程的销毁
void pool_destroy() {
	Task *head;
	while(pool->queue_head != NULL) {
		head = pool->queue_head;
		pool->queue_head = pool->queue_head->next;
		free(head);
	}

	pthread_mutex_destroy(&pool->taskLock);
	pthread_mutex__destroy(&pool->newTask);
	free(pool);
}

int main() {
	pool_init();
	sleep(1);
	for (int i = 1; i < 20; i++) {
		pool_add_task(i);
	}

	sleep(5);
	pool_destory();


}

运行结果:

编译错误:

error: ‘ThreadPool {aka struct ThreadPool}’ has no member named ‘head’

意义:ThreadPool 结构体没有head这个成员。

解决:检查是否拼写错误。

error: too few arguments to function ‘pthread_mutex_init’

意思:pthread_mutex_init这个函数参数少了

解决:检查函数的参数,添加对应的参数

线程的GDB调试

 显示线程:

info thread

切换线程:

thread id

GDB为特定线程设置断点:

break location thread id

GDB设置线程锁:

set scheduler-locking on/off

on:其他线程会暂停,可以单独调试一个线程

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件工程】为什么要选择软件工程专业?

个人主页&#xff1a;【&#x1f60a;个人主页】 文章目录前言软件工程&#x1f4bb;&#x1f4bb;&#x1f4bb;就业岗位&#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f4bb;就业前景&#x1f6e9;️&#x1f6e9;️&#x1f6e9;️工作环…

趣谈之什么是 API 货币化?

本文介绍了 API 货币化和 APISIX 实现 API 货币化方法。 作者刘维&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Contributor 原文链接 什么是 API 货币化 想象你开发并部署了一个服务&#xff0c;能够搜集你所在城市所有超市的打折和优惠信息&#xff0c;其他的…

C生万物 | 校招热门考点 —— 结构体内存对齐

文章目录一、前言结构体偏移量计算&#xff1a;offsetof二、规则介绍例题的分解与细说三、习题演练1、练习①2、练习②四、为什么存在内存对齐?1、平台原因(移植原因)2、性能原因五、如何修改默认对齐数六、实战演练✍一道百度笔试题&#xff1a; offsetof 宏的实现&#x1f4…

深度学习基础篇之深度神经网络(DNN)

神经网络不应该看做是一个算法&#xff0c;应该看做是一个特征挖掘方法。在实际的业界发展过程中&#xff0c;数据的作用往往大于模型&#xff0c;当我们把数据的隐藏特征提取出来之后&#xff0c;用很简单的模型也能预测的很好。 神经网络模型由生物神经中得到启发。在生物神…

【Linux】Makefile的简述

目录 前言&#xff1a; 一、Makefile的规则 二、Makefile的函数语法 &#xff08;1&#xff09;通配符pattern ​&#xff08;2&#xff09; 删除clean ​&#xff08;3&#xff09; 立即变量、延时变量 &#xff08;4&#xff09; Makefile常用函数 3-1.Makefile要达到…

第11章_常用类和基础API

第11章_常用类和基础API 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. 字符串相关类之不可变字符序列&#xff1a;String 1.1 String的特性 java.lang.String 类代表字符串…

vue之--使用TypeScript

搭配 TypeScript 使用 Vue​ 像 TypeScript 这样的类型系统可以在编译时通过静态分析检测出很多常见错误。这减少了生产环境中的运行时错误&#xff0c;也让我们在重构大型项目的时候更有信心。通过 IDE 中基于类型的自动补全&#xff0c;TypeScript 还改善了开发体验和效率。…

2023年美赛春季赛 Y题详细思路

由于今年各种各样的原因&#xff0c;导致美赛头一次&#xff0c;据说也将是最后一次&#xff0c;临时调整&#xff0c;加设春季赛。这对于急需建模奖项的大家来说是一个很好的机会。无论怎样的原因&#xff0c;今年美赛我们可能有所遗憾。但&#xff0c;春季赛也许就是弥补遗憾…

HTML4.1表单标签

input&#xff08;登录、注册、搜索功能&#xff09; type属性值类型称号展示类型text文本框placeholder占位符password密码框placeholder占位符radio单选框name checked&#xff08;默认选中&#xff09;同类型单选checkbox复选框 checked file 文件选择multiple多文件选择s…

分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测

分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测 目录分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测分类效果模型描述程序设计参考资料分类效果 模型描述 Matlab实现CNN-GRU-Attention多变量分类预测 1.data为数据集&#xff0c;格式为excel&#xff0c;12个输…

集合-LinkedList

LinkedList LinkedList的概述 LinkedList的底层使用双向链表实现。 链表是一种线性数据结构&#xff0c;其中每个元素都是一个单独的对象&#xff0c;包含一个指向列表中下一个节点的引用。 它可以用于实现各种抽象数据类型&#xff0c;例如列表、堆栈、队列等。 LinkedLis…

安装Nginx——docker安装

使用docker安装Nginx 1.开启docker systemctl start docker docker search nginx[rootlocalhost ~]# systemctl start docker //开启docker [rootlocalhost ~]# docker search nginx //搜素镜像 2. docker pull nginxdocker imagesdocker run -…

如何将录音转成文字?

在现代社会中&#xff0c;随着语音技术的不断发展和普及&#xff0c;将录音转换为文字变得越来越容易。无论是为了记录会议、面试、讲座、采访&#xff0c;还是为了记录个人的思考和想法&#xff0c;将录音转换为文字是一种方便快捷的方式。本文将介绍几种将录音转换为文字的方…

计算机系统结构教程-第七章-储存系统笔记(1)

7.1储存系统的层次结构 概述 理想的储存器&#xff1a;容量大、速度快、价格低。 但以上三种要求在实际应用中是相互矛盾&#xff1a; &#xff08;1&#xff09;速度快&#xff0c;价格高。 &#xff08;2&#xff09;容量大&#xff0c;价格低。 &#xff08;3&#xf…

ESLint检测VUE和JSON文件

ESLint 默认只支持检测JS文件中的文件&#xff0c;无法识别其它类型的文件&#xff0c;如果需要检测其它类型的文件就需要安装并指定对应的处理器&#xff0c;有点类似webpack的loader 处理vue文件 使用ESLint默认的处理器处理Vue文件大多数情况下会收到一个这样的错误。 Pa…

贪心算法

章节目录&#xff1a;一、算法介绍二、应用场景-集合覆盖问题2.1 问题引出2.2 思路分析2.3 代码示例三、结束语一、算法介绍 贪心算法&#xff08;greedy algorithm &#xff0c;又称贪婪算法&#xff09;是指&#xff0c;在对问题求解时&#xff0c;总是做出在当前看来是最好的…

Vue04_事件绑定_methods

v-on:事件名"表达式" methods: 定义回调函数 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><div id"app"><!--eve…

12、Qt生成dll方式-libs方式使用

Qt创建dll&#xff0c;使用LIBS -L$PWD -lxxx的方式调用dll 一、创建项目 1、打开Qt->新建文件->其他项目->Empty qmake Project->Choose... 2、输入项目名->选择位置->下一步 3、MinGW->下一步 4、默认&#xff0c;完成 5、在.pro中添加TEMPLATE sub…

C51单片机按键控制流水灯模式(定时器版本)以及定时器时钟

上篇文章我们学了关于定时器的三大组成部分及许多寄存器的概念问题&#xff0c;这篇文章我们就要开始讲解实操部分。 首先&#xff0c;我们先来看看本文最后写成的代码&#xff1a; 以上三张是代码的主函数&#xff0c;此外&#xff0c;代码中还需用到的独立按键检测代码在下面…

【Linux】回车与换行的区别+简单实现倒计时和进度条(学以致用)

前言&#xff1a;本文主要讲解回车与换行的区别&#xff0c;理解完回车与换行的区别后&#xff0c;我们将带大家实现一个简单的倒计时程序&#xff0c;会利用到本文学习的回车与换行&#xff0c;做到学以致用。 文章目录一.理解回车与换行(1)\r和\n都存在(2)\r和\n都不存在(3) …