线程池以及日志类的实现
目录
线程池:
日志类:
可变参数以及相关函数
1.va_list
2. va_start
3. va_end
日志Log类
线程池
线程池:
是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着
监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量
日志类:
在代码中 我对可变参数进行了处理,以下是对可变参数的补充
可变参数以及相关函数
可变参数包含在#include <stdarg.h>这个库中
1.va_list
va_list是一种类型,用于存储可变参数的状态。它通常声明在函数内部,表示一个参数列表。
2. va_start
va_start宏用于初始化一个va_list对象,使其指向可变参数列表的第一个参数。它需要两个参数:一个是va_list对象,另一个是紧接在可变参数列表之前的最后一个已知参数的名字。
3. va_end
va_end宏用于清理由va_start初始化的va_list对象。在处理完可变参数后,必须调用va_end。
例子:
#include <stdarg.h>
#include <stdio.h>// 定义一个接受可变参数的函数
void printNumbers(int num, ...) {va_list args; // 声明va_list类型的变量va_start(args, num); // 初始化va_list变量,使其指向第一个可变参数for (int i = 0; i < num; i++) {int value = va_arg(args, int); // 获取下一个参数,类型为intprintf("%d ", value);}va_end(args); // 清理va_list变量printf("\n");
}int main() {printNumbers(3, 10, 20, 30); // 调用函数,传递三个参数printNumbers(5, 1, 2, 3, 4, 5); // 调用函数,传递五个参数return 0;
}
日志Log类
#pragma once
#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include "LockGuard.hpp"
bool gIsSave = false;
std::string logname = "log.txt";
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;// 1. 日志是由等级的
enum Level
{DEBUG = 0,INFO,WARNING,ERROR,FATAL
};std::string LevelToString(int level)
{switch (level){case DEBUG:return "DEBUG";case INFO:return "INFO";case WARNING:return "WARNING";case ERROR:return "ERROR";case FATAL:return "FATAL";default:return "UNKOWN";}
}void Savefile(std::string &filename, std::string &message)
{std::ofstream out(filename, std::ios::app);if (!out.is_open()){return;}out << message;out.close();
}std::string Gettime()
{time_t currtime = time(nullptr);struct tm *fromatetime = localtime(&currtime);if (fromatetime == nullptr){return "ERROR";}char buffer[1024];snprintf(buffer, sizeof(buffer), "%d-%d-%d-%d-%d-%d",fromatetime->tm_year + 1900,fromatetime->tm_mon + 1,fromatetime->tm_mday,fromatetime->tm_hour,fromatetime->tm_min,fromatetime->tm_sec);return buffer;
}void Logmessage(int level, int line, std::string filename, const char *format, ...)
{std::string clevel = LevelToString(level);std::string time = Gettime();pid_t selfpid = getpid();va_list arg;char buffer[1024];va_start(arg, format);//可变参数处理vsnprintf(buffer, sizeof(buffer), format, arg);va_end(arg);std::string message = "[" + time + "]" + "[" + clevel + "]" +"[" + std::to_string(selfpid) + "]" +"[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";LookGuard Lookguard(&lock);if (!gIsSave){std::cout<<message<<std::endl;}else{Savefile(logname, message);}
}#define LOG(level,format,...) do{Logmessage(level,__LINE__,__FILE__,format,##__VA_ARGS__);}while(0)//c99新增处理可变参数 +##支持没有可变参数时 代码块整体替换 do while(0)
#define EnableFile() do{gIsSave=true;}while(0)
#define Enablescreem() do{gIsSave=false;}while(0)
我基于Linux下pthread.h对线程相关的接口进行了封装
#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <functional>
#include <pthread.h>using func_t = std::function<void(std::string)>;
class Thread
{
public:void Excute(){_func(_threadname);}public:Thread(func_t func, std::string name = "none-name"): _func(func), _threadname(name), _stop(true){}static void *threadroutine(void *args) // 类成员函数,形参是有this指针的!!{Thread *self = static_cast<Thread *>(args);self->Excute();return nullptr;}bool Start(){int n = pthread_create(&_tid, nullptr, threadroutine, this);if (!n){_stop = false;return true;}else{return false;}}void Detach(){if (!_stop){pthread_detach(_tid);}}void Join(){if (!_stop){pthread_join(_tid, nullptr);}}std::string name(){return _threadname;}void Stop(){_stop = true;}~Thread() {}private:pthread_t _tid;std::string _threadname;func_t _func;bool _stop;
};
再进行封装之后,便可以进行线程池的搭建了
线程池
#pragma once
#include <memory>
#include <vector>
#include <queue>
#include <ctime>
#include "log.hpp"
#include "thread.hpp"
const static int gthreadnum = 5;template <typename T>
class threadpool
{private:void QueueLock(){pthread_mutex_lock(&_mutex);}void QueueUnlock(){pthread_mutex_unlock(&_mutex);}void WakeThread(){pthread_cond_signal(&_cond);}void WakeAllThread(){pthread_cond_broadcast(&_cond);}void Threadsleep(){pthread_cond_wait(&_cond, &_mutex);}public:threadpool(int threadnum = gthreadnum): _threadnum(threadnum), _waitnum(0), _Isrunning(false),_Startnum(0){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);}~threadpool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}void HandlerTask(std::string name){while (true){QueueLock();while (_taskqueue.empty() && _Isrunning) // 空的但是还在跑{_waitnum++;Threadsleep(); // 去阻塞等待_waitnum--;}if (_taskqueue.empty() && !_Isrunning) // 空的而且没跑了{QueueUnlock();std::cout << name << ":quit" << std::endl;break;}// 2.2 如果线程池不退出 && 任务队列不是空的// 2.3 如果线程池已经退出 && 任务队列不是空的 --- 处理完所有的任务,然后在退出// 3. 一定有任务, 处理任务T t = _taskqueue.front();_taskqueue.pop();if(t()){std::cout<<"mission success"<<std::endl;} // 执行else{std::cout<<"mission fail"<<std::endl;}QueueUnlock();}}bool Enqueue(const T &x){bool ret = false;QueueLock();if (_Isrunning){++_Startnum;LOG(INFO,"%s","ENqueue mission");_taskqueue.push(x);if (_waitnum > 0){WakeThread();}ret = true;}QueueUnlock();return ret;}void InitThreadPool(){for (int num = 0; num < _threadnum; num++){std::string name = "Thread:" + std::to_string(num + 1);_threadpool.emplace_back(std::bind(&threadpool::HandlerTask, this, std::placeholders::_1), name); // bind绑定类成员函数时,第二个参数必须是this}LOG(INFO,"%s","InitPool");_Isrunning = true;}bool ReadyToStart(){LOG(INFO,"%s","ReadToStart");return _Startnum==_threadnum;}void Stop(){QueueLock();_Isrunning = false;WakeAllThread(); // 不跑了 把剩的任务跑了 唤醒在_cond下等待的所有线程 并执行LOG(WARNING,"%s","STOP");QueueUnlock();}void Wait(){for (auto &thread : _threadpool){LOG(INFO,"%s:-%s",thread.name().c_str(),"wait");thread.Join();}}void Start(){for (auto &thread : _threadpool){LOG(INFO,"%s:-%s",thread.name().c_str(),"start");thread.Start();}}private:int _threadnum;std::vector<Thread> _threadpool;std::queue<T> _taskqueue;pthread_mutex_t _mutex;pthread_cond_t _cond;int _waitnum;bool _Isrunning;int _Startnum;
};
相关文章:
线程池以及日志类的实现
目录 线程池: 日志类: 可变参数以及相关函数 1.va_list 2. va_start 3. va_end 日志Log类 线程池 线程池: 是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着 监督管理者分配可并发执行…...
基于长短期记忆网络 LSTM 的送餐时间预测
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对…...
K-means聚类算法详细介绍
目录 🍉简介 🍈K-means聚类模型详解 🍈K-means聚类的基本原理 🍈K-means聚类的算法步骤 🍈K-means聚类的优缺点 🍍优点 🍍缺点 🍈K-means聚类的应用场景 🍈K-mea…...
SAP FS00如何导出会计总账科目表
输入T-code : S_ALR_87012333 根据‘FS00’中找到的总账科目,进行筛选执行 点击左上角的列表菜单,选择‘电子表格’导出即可...
ROS参数服务器
一、介绍 参数服务器是用于存储和检索参数的分布式多机器人配置系统,它允许节点动态地获取参数值。 在ROS中,参数服务器是一种用于存储和检索参数的分布式多机器人配置系统。它允许节点动态地获取参数值,并提供了一种方便的方式来管理和共享配…...
QCC---DFU升级变更设备名和地址
QCC---DFU升级变更设备名和地址 这个很多人碰到这个疑问,升级了改不了设备名和地址 /******************************************************************************* Copyright (c) 2018 Qualcomm Technologies International, Ltd. FILE NAME sink_dfu_ps.c DESCRIPT…...
[力扣题解] 695. 岛屿的最大面积
题目:695. 岛屿的最大面积 思路 代码 深度优先搜索 // 深度搜索 class Solution { private:int area_max 0;int dir[4][2] {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};void dfs(vector<vector<int>>& grid, vector<vector<bool>>& …...
AI模型发展路径探析:开源与闭源,何者更胜一筹?
AI模型发展路径探析:开源与闭源,何者更胜一筹? 在当今快速发展的人工智能领域,AI模型成为推动技术创新和应用落地的关键。而评价一个AI模型“好不好”“有没有发展”,往往会引向一个重要话题:开源与闭源这…...
concurrency 并行编程
Goroutine go语言的魅力所在,高并发。 线程是操作系统调度的一种执行路径,用于在处理器执行我们在函数中编写的代码。一个进程从一个线程开始,即主线程,当该线程终止时,进程终止。这是因为主线程是应用程序的原点。然后…...
JavaScript如何让一个按钮的点击事件在完成之前禁用
在JavaScript中,要禁用一个按钮的点击事件直到某个操作完成,你可以将其点击事件用匿名函数的方式书写。 你可以将其在点击函数内设置为null来禁用按钮。 <button id"butto_n">点击抽奖</button><script>butto_n.onclick bu…...
透视App投放效果,Xinstall助力精准分析,让每一分投入都物超所值!
在移动互联网时代,App的推广与投放成为了每一个开发者和广告主必须面对的问题。然而,如何精准地掌握投放效果,让每一分投入都物超所值,却是一个令人头疼的难题。今天,我们就来谈谈如何通过Xinstall这个专业的App全渠道…...
【Linux杂货铺】进程通信
目录 🌈 前言🌈 📁 通信概念 📁 通信发展阶段 📁 通信方式 📁 管道(匿名管道) 📂 接口 编辑📂 使用fork来共享通道 📂 管道读写规则 &…...
常用API(正则表达式、爬取、捕获分组和非捕获分组 )
1、正则表达式 练习——先爽一下正则表达式 正则表达式可以校验字符串是否满足一定的规则,并用来校验数据格式的合法性。 需求:假如现在要求校验一个qq号码是否正确。 规则:6位及20位之内,0不能在开头,必须全部是数字…...
JVM学习-Class文件结构②
访问标识(access_flag) 在常量池后,紧跟着访问标记,标记使用两个字节表示,用于识别一些类或接口层次的访问信息,包括这个Class是类还是接口,是否定义为public类型,是否定义为abstract类型,如果…...
数据库连接项目
MySQL...
MySQL--InnoDB体系结构
目录 一、物理存储结构 二、表空间 1.数据表空间介绍 2.数据表空间迁移 3.共享表空间 4.临时表空间 5.undo表空间 三、InnoDB内存结构 1.innodb_buffer_pool 2.innodb_log_buffer 四、InnoDB 8.0结构图例 五、InnoDB重要参数 1.redo log刷新磁盘策略 2.刷盘方式&…...
ffplay 使用文档介绍
ffplay ffplay 是一个简单的媒体播放器,它是 FFmpeg 项目的一部分。FFmpeg 是一个广泛使用的多媒体框架,能够解码、编码、转码、复用、解复用、流化、过滤和播放几乎所有类型的媒体文件。 ffplay 主要用于测试和调试,因为它提供了一个命令行界面,可以方便地查看媒体文件的…...
四种网络IO模型
📝个人主页:五敷有你 🔥系列专栏:面经 ⛺️稳中求进,晒太阳 IO的定义 IO是计算机内存与外部设备之间拷贝数据的过程。CPU访问内存的速度远高于外部设备。因此CPU是先把外部设备的数据读取到内存,在…...
Mixed-precision计算原理(FP32+FP16)
原文: https://lightning.ai/pages/community/tutorial/accelerating-large-language-models-with-mixed-precision-techniques/ This approach allows for efficient training while maintaining the accuracy and stability of the neural network. In more det…...
Go 控制协程(goroutine)的并发数量
在使用协程并发处理某些任务时, 其并发数量往往因为各种因素的限制不能无限的增大. 例如网络请求、数据库查询等等。 从运行效率角度考虑,在相关服务可以负载的前提下(限制最大并发数),尽可能高的并发。 在Go语言中,…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
