当前位置: 首页 > news >正文

线程池以及日志类的实现

目录

线程池:

日志类:

可变参数以及相关函数

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类 线程池 线程池: 是一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着 监督管理者分配可并发执行…...

基于长短期记忆网络 LSTM 的送餐时间预测

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…...

K-means聚类算法详细介绍

目录 &#x1f349;简介 &#x1f348;K-means聚类模型详解 &#x1f348;K-means聚类的基本原理 &#x1f348;K-means聚类的算法步骤 &#x1f348;K-means聚类的优缺点 &#x1f34d;优点 &#x1f34d;缺点 &#x1f348;K-means聚类的应用场景 &#x1f348;K-mea…...

SAP FS00如何导出会计总账科目表

输入T-code : S_ALR_87012333 根据‘FS00’中找到的总账科目&#xff0c;进行筛选执行 点击左上角的列表菜单&#xff0c;选择‘电子表格’导出即可...

ROS参数服务器

一、介绍 参数服务器是用于存储和检索参数的分布式多机器人配置系统&#xff0c;它允许节点动态地获取参数值。 在ROS中&#xff0c;参数服务器是一种用于存储和检索参数的分布式多机器人配置系统。它允许节点动态地获取参数值&#xff0c;并提供了一种方便的方式来管理和共享配…...

QCC---DFU升级变更设备名和地址

QCC---DFU升级变更设备名和地址 这个很多人碰到这个疑问,升级了改不了设备名和地址 /******************************************************************************* Copyright (c) 2018 Qualcomm Technologies International, Ltd. FILE NAME sink_dfu_ps.c DESCRIPT…...

[力扣题解] 695. 岛屿的最大面积

题目&#xff1a;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模型发展路径探析&#xff1a;开源与闭源&#xff0c;何者更胜一筹&#xff1f; 在当今快速发展的人工智能领域&#xff0c;AI模型成为推动技术创新和应用落地的关键。而评价一个AI模型“好不好”“有没有发展”&#xff0c;往往会引向一个重要话题&#xff1a;开源与闭源这…...

concurrency 并行编程

Goroutine go语言的魅力所在&#xff0c;高并发。 线程是操作系统调度的一种执行路径&#xff0c;用于在处理器执行我们在函数中编写的代码。一个进程从一个线程开始&#xff0c;即主线程&#xff0c;当该线程终止时&#xff0c;进程终止。这是因为主线程是应用程序的原点。然后…...

JavaScript如何让一个按钮的点击事件在完成之前禁用

在JavaScript中&#xff0c;要禁用一个按钮的点击事件直到某个操作完成&#xff0c;你可以将其点击事件用匿名函数的方式书写。 你可以将其在点击函数内设置为null来禁用按钮。 <button id"butto_n">点击抽奖</button><script>butto_n.onclick bu…...

透视App投放效果,Xinstall助力精准分析,让每一分投入都物超所值!

在移动互联网时代&#xff0c;App的推广与投放成为了每一个开发者和广告主必须面对的问题。然而&#xff0c;如何精准地掌握投放效果&#xff0c;让每一分投入都物超所值&#xff0c;却是一个令人头疼的难题。今天&#xff0c;我们就来谈谈如何通过Xinstall这个专业的App全渠道…...

【Linux杂货铺】进程通信

目录 &#x1f308; 前言&#x1f308; &#x1f4c1; 通信概念 &#x1f4c1; 通信发展阶段 &#x1f4c1; 通信方式 &#x1f4c1; 管道&#xff08;匿名管道&#xff09; &#x1f4c2; 接口 ​编辑&#x1f4c2; 使用fork来共享通道 &#x1f4c2; 管道读写规则 &…...

常用API(正则表达式、爬取、捕获分组和非捕获分组 )

1、正则表达式 练习——先爽一下正则表达式 正则表达式可以校验字符串是否满足一定的规则&#xff0c;并用来校验数据格式的合法性。 需求&#xff1a;假如现在要求校验一个qq号码是否正确。 规则&#xff1a;6位及20位之内&#xff0c;0不能在开头&#xff0c;必须全部是数字…...

JVM学习-Class文件结构②

访问标识(access_flag) 在常量池后&#xff0c;紧跟着访问标记&#xff0c;标记使用两个字节表示&#xff0c;用于识别一些类或接口层次的访问信息&#xff0c;包括这个Class是类还是接口&#xff0c;是否定义为public类型&#xff0c;是否定义为abstract类型&#xff0c;如果…...

数据库连接项目

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模型

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;面经 ⛺️稳中求进&#xff0c;晒太阳 IO的定义 IO是计算机内存与外部设备之间拷贝数据的过程。CPU访问内存的速度远高于外部设备。因此CPU是先把外部设备的数据读取到内存&#xff0c;在…...

Mixed-precision计算原理(FP32+FP16)

原文&#xff1a; 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)的并发数量

在使用协程并发处理某些任务时, 其并发数量往往因为各种因素的限制不能无限的增大. 例如网络请求、数据库查询等等。 从运行效率角度考虑&#xff0c;在相关服务可以负载的前提下&#xff08;限制最大并发数&#xff09;&#xff0c;尽可能高的并发。 在Go语言中&#xff0c;…...

告别DLL缺失烦恼!Visual C++运行库合集一键搞定Windows应用依赖问题

告别DLL缺失烦恼&#xff01;Visual C运行库合集一键搞定Windows应用依赖问题 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经在打开某个软件或游戏时…...

AWS DevOps Agent 完全指南

AWS DevOps Agent 是 AWS 推出的前沿 AI 运维代理,自主调查和解决事件、持续预防故障、提升系统可靠性。本文档覆盖从原理到实战的全生命周期管理。 一、定位与价值 一句话定义 AWS DevOps Agent = AI 驱动的 SRE 队友,724 自主调查告警、定位根因、生成修复方案、预防未来…...

Redis 客户端连接详解

Redis 客户端连接详解 引言 Redis 是一款高性能的内存数据结构存储系统,常用于缓存、会话管理、实时排行榜等功能。客户端连接是 Redis 生态系统中的重要组成部分,本文将详细介绍 Redis 客户端连接的相关知识,包括连接方式、连接配置、连接管理等方面。 Redis 客户端连接…...

基于Atmega 1284P的16位复古计算器:硬件设计与软件实现全解析

1. 项目概述与核心思路最近在整理工作室时&#xff0c;翻出了一堆老旧的7段数码管和矩阵键盘&#xff0c;看着这些充满复古气息的元件&#xff0c;一个想法冒了出来&#xff1a;为什么不自己动手做一台复古风格的计算器呢&#xff1f;不是那种用液晶屏显示的现代计算器&#xf…...

YOLOv8道路交通信号标志识别检测系统(项目源码+YOLO数据集+模型权重+UI界面+python+深度学习+环境配置)

摘要 道路交通信号标志的自动检测是智能驾驶与交通管理系统中的核心环节。本文基于YOLOv8目标检测算法&#xff0c;构建了一个涵盖21类常见交通信号标志的检测系统&#xff0c;包括禁令标志、指示标志、警告标志及信号灯等。模型在包含1376张训练图像、488张验证图像和229张测…...

2023B卷,最佳植树距离

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:华为OD面试 文章目录 一、🍀前言 1.1 ☘️题目详情 1.2 ☘️参考解题答案 一、🍀前言 2023B卷,最佳植树距离。 1.1 ☘️题目详情 题目: 小明在直…...

污水管网在线监测系统,精准定位污水偷排源头

当前&#xff0c;城市地下排水管网普遍存在“看不见、摸不着”的监管难题。污水偷排、漏检等现场层出不穷&#xff0c;依赖人工进行监测管理的方式无疑是十分困难的。因此&#xff0c;管理部门需要灵活运用先进技术&#xff0c;积极转变观念&#xff0c;实现对污水管网的定量、…...

CSS盒模型完全指南

CSS盒模型完全指南 引言 CSS盒模型是理解CSS布局的基础&#xff0c;每个HTML元素都可以看作一个矩形盒子。本文将深入探讨盒模型的核心概念、使用方法和最佳实践。 一、盒模型基础 1.1 盒模型组成 .element {width: 300px;height: 200px;padding: 20px;border: 5px solid #333;…...

LeetCode 每日一题笔记 日期:2026.05.24 题目:1340. 跳跃游戏 V

LeetCode 每日一题笔记 0. 前言 日期&#xff1a;2026.05.24题目&#xff1a;1340. 跳跃游戏 V难度&#xff1a;困难标签&#xff1a;数组、动态规划、记忆化搜索、单调栈 1. 题目理解 问题描述&#xff1a; 给定一个整数数组 arr 和整数 d&#xff0c;从下标 i 出发&#xff0…...

终极指南:如何快速解锁网易云NCM加密音乐,实现格式自由转换

终极指南&#xff1a;如何快速解锁网易云NCM加密音乐&#xff0c;实现格式自由转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否曾为网易云音乐下载的NCM格式文件无法在其他设备播放而烦恼&#xff1f;ncmdump作为一款高效…...