线程池以及日志类的实现

目录

线程池:

日志类:

可变参数以及相关函数

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;
};

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

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

相关文章

Flutter 中的 ExpansionPanelList 小部件:全面指南

Flutter 中的 ExpansionPanelList 小部件&#xff1a;全面指南 在Flutter中&#xff0c;ExpansionPanelList是一个展示可展开/折叠面板列表的组件&#xff0c;它允许用户通过点击来展开或折叠列表中的各个面板。这种组件非常适合展示FAQ、设置选项或其他需要分组和隐藏内容的场…

Flutter中的CustomScrollView详解及使用指南

在Flutter开发中&#xff0c;CustomScrollView 是一个非常强大的滚动控件&#xff0c;它允许我们创建自定义的滚动效果和布局。相比于普通的ListView或GridView&#xff0c;CustomScrollView 提供了更大的灵活性&#xff0c;适用于更复杂的布局需求。本文将详细介绍CustomScrol…

零基础HTML教程(33)--HTML5表单新功能

文章目录 1. 背景2. HTML5新增表单元素2.1 number (数字输入框)2.2 email (邮箱输入框)2.3 url (链接输入框)2.4 tel (电话输入框)2.5 range (范围选择框)2.6 color (颜色选择框)2.7 datetime (日期时间选择框)2.8 search (搜索框) 3. placeholder &#xff08;占位属性&#x…

前后端分离的好处

进行前后端分离开发的原因主要归结于以下几个方面&#xff1a; 提升开发效率&#xff1a;前后端分离允许前端和后端团队独立工作&#xff0c;他们可以并行开发&#xff0c;不需要等待对方完成才能开始自己的工作。这样可以大大缩短开发周期&#xff0c;加快产品上市时间。 职责…

站在ESG“20+”新起点上,看中国ESG先锋探索力量

全链减碳、建设绿色工厂、打造零碳产品、守护生物多样性、向受灾群众捐助……不知你是否察觉&#xff0c;自“双碳”目标提出以来&#xff0c;一股“可持续发展热潮”正覆盖各行各业&#xff0c;并且渗透到我们衣食住行的方方面面。在资本市场&#xff0c;ESG投资热潮更是席卷全…

TemperMonkey用于通义千问网页版回答完毕自动朗读的脚本代码

// UserScript // name 通义千问回答完毕-朗读结果 // namespace http://tampermonkey.net/ // version 2024-04-26 // description try to take over the world! // author You // match https://tongyi.aliyun.com/qianwen* // icon h…

AI爆文写作:要写文章爆,这47个爆文前缀少不了!

47个爆文前缀:很震惊很好用 这些前缀,虽然被用了无数次,但每个人看到还是会忍不住点进去。 可以借鉴这样强情绪的句式。 序号前缀1就在刚刚…2真相曝光…3震惊国人…4惊天秘密…5疯狂转发…6删前速看…7千万别吃…8还敢喝吗…9癌症前兆…10赶快扔了…11太可怕了…12大事不…

1-3RT-Thread内核基础-笔记

RT-Thread内核相关的概念与基础知识 其中内核库是为了保证内核能够独立运行的一套小型的类似C库的函数实现子集。这部分根据编译器的不同&#xff0c;自带C库的情况也会有些不同。 内核最小的资源占用情况是3K的ROM和1.2K的RAM。 RT thread系统启动流程 启动文件&#xff0c;此…

智慧仓储新动力:EasyCVR+AI视频智能监管系统方案助力仓储安全高效管理

一、背景 随着物流行业的快速发展和智能化水平的提升&#xff0c;智慧仓储视频智能监管系统已成为现代仓储管理的重要组成部分。本系统通过综合运用物联网、视频分析、边缘计算等技术手段&#xff0c;实现对仓储环境的全面监控、智能分析和高效管理。 TSINGSEE青犀视频汇聚Ea…

【启明智显技术分享】SOM2D02-2GW核心板适配ALSA(适用Sigmastar ssd201/202D)

提示&#xff1a;作为Espressif&#xff08;乐鑫科技&#xff09;大中华区合作伙伴及sigmastar&#xff08;厦门星宸&#xff09;VAD合作伙伴&#xff0c;我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考。同时也用心整理了乐鑫及星宸…

IPIDEA与您分享:代理IP究竟是如何保护用户隐私的?

在信息化、网络化的今天&#xff0c;互联网已成为人们生活中不可或缺的一部分。无论是日常沟通、学习工作&#xff0c;还是娱乐休闲&#xff0c;网络都扮演着举足轻重的角色。然而&#xff0c;随着网络活动的增加&#xff0c;网络安全问题也日益凸显&#xff0c;为了保护个人隐…

前端 CSS 经典:元素倒影

前言&#xff1a;好看的元素倒影&#xff0c;可以通过-webkit-box-reflect 实现。但有兼容问题&#xff0c;必须是 webkit 内核的浏览器&#xff0c;不然没效果。但是好看啊。 效果图&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"&g…

【C++】<图形库> 三人成棋(面向对象写法)

目录 一、游戏需求 二、程序架构 三、代码实现 四、实现效果 五、已知BUG 一、游戏需求 构建一个五子棋游戏&#xff0c;在自定义棋盘宽度和高度的基础上&#xff0c;实现三人对战功能&#xff0c;并且能判定谁输谁赢。 二、程序架构 (1) 对象分析&#xff1a; 【1】 需…

监控服务器性能指标,提升服务器性能

服务器是网络中最关键的组件之一&#xff0c;混合网络架构中的每个关键活动都以某种方式与服务器操作相关&#xff0c;服务器不仅是现代计算操作的支柱&#xff0c;也是网络通信的关键。 从发送电子邮件到访问数据库和托管应用程序&#xff0c;服务器的可靠性和性能直接影响到…

揭秘循环购模式:消费返利新玩法,引领电商新潮流

在当今的消费市场中&#xff0c;有一种商业模式引起了广大消费者的热烈讨论——那就是循环购模式。你可能会想&#xff0c;消费满千元就能得到两千元的福利&#xff0c;每天还能领取现金&#xff0c;这怎么可能呢&#xff1f;商家难道真的在“慷慨解囊”&#xff1f;今天&#…

数据结构_链式二叉树(Chained binary tree)基础

✨✨所属专栏&#xff1a;数据结构✨✨ ✨✨作者主页&#xff1a;嶔某✨✨ 二叉树的遍历 前序、中序以及后序遍历 学习二叉树结构&#xff0c;最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则&#xff0c;依次对二叉树中的结点进行相应的操作&#xff…

Docker(三) 容器管理

1 容器管理概述 Docker 的容器管理可以通过 Docker CLI 命令行工具来完成。Docker 提供了丰富的命令&#xff0c;用于管理容器的创建、启动、停止、删除、暂停、恢复等操作。 以下是一些常用的 Docker 容器命令&#xff1a; 1、docker run&#xff1a;用于创建并启动一个容器。…

声量 2024 | 从小到大,有哪些好产品曾出现在我们生活里?

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 老段 运营 / SandLiu 卷圈 监制 / 姝琦 封面 / 姝琦 产品统筹 / bobo 场地支持 / 阿那亚 联合制作 / 声量The Power of Voice 特别鸣谢 / 深夜谈谈播客网络 本期节目录制于第二届「声量The Power of Voice」现场。 在…

Visual Studio调用matlab的二种方式及区别

VS调用matlab的方式有两种&#xff1a; 方式1调用MATLAB引擎 首先&#xff0c;添加头文件 #include “engine.h” 然后&#xff0c;引用函数调用依赖库(lib) libeng.lib libmx.lib libmat.lib&#xff0c;之后就可以调用MATLAB引擎。 方式2调用MATLAB生成的dll 调用MATLAB生…

如何在VSCode中修改默认终端

如何在VSCode中修改默认终端 步骤1: 打开设置步骤2: 搜索终端设置步骤3: 配置默认终端Windows:macOS:Linux: 步骤4: 保存设置 在VSCode中修改默认终端的步骤如下&#xff1a; 步骤1: 打开设置 点击左下角的齿轮图标&#xff0c;选择“设置”(或者使用快捷键 Ctrl , on Windo…