Linux--线程池(包含日志的解释)

线程系列:
Linux–线程的认识(一)
Linux–线程的分离、线程库的地址关系的理解、线程的简单封装(二)
线程的互斥:临界资源只能在同一时间被一个线程使用
生产消费模型
信号量

线程池

线程池(Thread Pool)是一种基于池化技术设计用于管理复用线程的机制
在多线程编程中,频繁地创建和销毁线程会消耗大量的系统资源,并且由于线程的创建和销毁需要时间,这也会降低程序的执行效率。线程池通过预先创建一定数量的线程并放入池中,需要时从池中取出线程执行任务,执行完毕后线程并不销毁而是重新放回池中等待下一次使用,从而避免了线程的频繁创建和销毁所带来的开销。

主要优点

  • 降低资源消耗:通过复用已存在的线程,减少线程创建和销毁的开销。
  • 提高响应速度:当任务到达时,可以立即分配线程进行处理,减少了等待时间。
  • 提高线程的可管理性:线程池可以统一管理线程,包括线程的创建、调度、执行和销毁等。

关键参数

  • 核心线程数:线程池维护线程的最少数量,即使这些线程处于空闲状态,线程池也不会回收它们(一般为主线程)。
  • 最大线程数:线程池中允许的最大线程数。
  • 阻塞队列:用于存放待执行的任务的队列。当线程池中的所有线程都忙时,新任务会被添加到这个队列中等待处理。
  • 非核心线程空闲存活时间:当线程池中的线程数量超过核心线程数时,如果线程空闲时间超过这个时间,多余的线程将被终止。
  • 线程工厂:用于创建新线程的工厂。
  • 拒绝策略:当线程池和队列都满了时,对于新来的任务将采取的拒绝策略。

实现原理

线程池的实现原理通常包括以下几个关键部分:

  • 线程池管理器:负责创建并管理线程池,包括初始化线程池、创建工作线程、销毁线程池等。
  • 工作线程:线程池中的线程,负责执行具体的任务。工作线程通常会不断从任务队列中取出任务并执行,直- 到线程池被销毁或所有任务都执行完毕。
  • 任务接口:每个任务必须实现的接口,用于定义任务的执行逻辑。在Java中,这通常是通过实现Runnable或Callable接口来实现的。
  • 任务队列:用于存放待处理的任务。当线程池中的工作线程数量达到最大值时,新到达的任务会被放入任务队列中等待处理。任务队列的实现通常依赖于Java的BlockingQueue接口。

实现流程

  • 当有新任务提交给线程池时,线程池会首先判断当前正在运行的线程数量是否小于核心线程数。如果是,则直接创建新的线程来执行任务;否则,将任务加入任务队列等待处理。
  • 如果任务队列已满,且当前正在运行的线程数量小于最大线程数(maximumPoolSize),则创建新的线程来处理任务;如果线程数量已经达到最大线程数,则根据配置的拒绝策略来处理新任务(如抛出异常、直接丢弃等)。
  • 当一个线程完成任务后,它会从任务队列中取下一个任务来执行;如果没有任务可供执行,并且线程池中的线程数量超过了核心线程数,且这些线程空闲时间超过了设定的存活时间,则这些线程会被销毁,直到线程池中的线程数量减少到核心线程数为止。

实例

Thread.hpp

#ifndef __THREAD_HPP__
#define __THREAD_HPP__#include<iostream>
#include<string>
#include<pthread.h>
#include<functional>
#include<unistd.h>using namespace std;namespace ThreadMdule
{using func_t = std::function<void(string)>;class Thread{public:void Excute(){_func(_threadname);}Thread(func_t func, const std::string &name="none-name"): _func(func), _threadname(name), _stop(true){}static void* threadroutine(void* args){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);}}string name(){return _threadname;}void Stop(){_stop = true;}~Thread() {}private:pthread_t _tid;std::string _threadname;func_t _func;bool _stop;};
}#endif

ThreadPool.hpp

#pragma once#include<iostream>
#include<vector>
#include<queue>
#include<pthread.h>
#include"Thread.hpp"
#include"Log.hpp"
#include"LockGuard.hpp"
using namespace ThreadMdule;
using namespace std;
const static int gdefaultthreadnum=3;//默认线程池的线程数template <class T>
class ThreadPool
{
public:ThreadPool(int threadnum=gdefaultthreadnum) :_threadnum(threadnum),_waitnum(0),_isrunning(false){pthread_mutex_init(&_mutex,nullptr);pthread_cond_init(&_cond,nullptr);LOG(INFO,"ThreadPool COnstruct.");}//各个线程独立的任务函数void HandlerTask(string name){LOG(INFO,"%s is running...",name.c_str());while(true){LockQueue();//开启保护//等到有任务时才退出循环执行下列语句while(_task_queue.empty()&&_isrunning){_waitnum++;ThreadSleep();_waitnum--;}//当任务队列空并且线程池停止时线程退出if(_task_queue.empty()&&!_isrunning){UnlockQueue();cout<<name<<" quit "<<endl;sleep(1);break;}//1.任务队列不为空&&线程池开启//2.任务队列不为空&&线程池关闭,直到任务队列为空//所以,只要有任务,就要处理任务T t=_task_queue.front();//取出对应任务_task_queue.pop();UnlockQueue();LOG(DEBUG,"%s get a task",name.c_str());//处理任务t();LOG(DEBUG,"%s handler a task,result is: %s",name.c_str(),t.ResultToString().c_str());}}//线程池中线程的构建void InitThreadPool(){for(int i=0;i<_threadnum;i++){string name="thread-"+to_string(i+1);_threads.emplace_back(bind(&ThreadPool::HandlerTask,this,placeholders::_1),name);LOG(INFO,"init thread %s done",name.c_str());}_isrunning=true;}//线程池的启动void Start(){for(auto& thread:_threads){thread.start();}}//线程池停止void Stop(){LockQueue();_isrunning=false;ThreadWakeupAll();UnlockQueue();}void Wait(){for(auto& thread:_threads){thread.Join();LOG(INFO,"%s is quit...",thread.name().c_str());}}//将任务入队列bool Enqueue(const T& t){bool ret=false;LockQueue();if(_isrunning){_task_queue.push(t);//如果有空闲的线程,那么唤醒线程让其执行任务if(_waitnum>0){ThreadWakeup();}LOG(DEBUG,"enqueue task success");ret=true;}UnlockQueue();return ret;}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}
private:void LockQueue(){pthread_mutex_lock(&_mutex);}void UnlockQueue(){pthread_mutex_unlock(&_mutex);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}void ThreadWakeup(){pthread_cond_signal(&_cond);}void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}int _threadnum;//线程数vector<Thread> _threads;//存储线程的vectorqueue<T> _task_queue;//输入的任务队列pthread_mutex_t _mutex;//互斥锁pthread_cond_t _cond;//条件变量int _waitnum;//空闲的线程数bool _isrunning;//表示线程池是否启动};

Task.hpp

#include<iostream>
#include<string>
#include<functional>
using namespace std;class Task
{
public:Task(){}Task(int a,int b): _a(a),_b(b),_result(0){}void Excute(){_result=_a+_b;}string ResultToString(){return to_string(_a) + "+"+to_string(_b)+"="+to_string(_result);}string DebugToString(){return to_string(_a) + "+" + to_string(_b) + "= ?";}void operator()(){Excute();}
private:int _a;int _b;int _result;
};

main.cc

int main()
{srand(time(nullptr)^getpid()^pthread_self());//EnableScreen();EnableFile();unique_ptr<ThreadPool<Task>> tp(new ThreadPool<Task>(5));tp->InitThreadPool();tp->Start();int tasknum=10;while(tasknum){sleep(1);int a=rand()%10+1;usleep(1024);int b=rand()%20+1;Task t(a,b);LOG(INFO,"main thread push task: %s",t.DebugToString().c_str());tp->Enqueue(t);tasknum--;}tp->Stop();tp->Wait();
}

Loh.hpp

#pragma once#include<iostream>
#include<fstream>
#include<ctime>
#include<cstdarg>
#include<string>
#include<sys/types.h>
#include<unistd.h>
#include<cstdio>
#include"LockGuard.hpp"using namespace std;bool gIsSave=false;//默认输出到屏幕
const string logname="log.txt";
//1.日志是有等级的
enum Level
{DEBUG=0,INFO,WARNING,ERROR,FATAL 
};void SaveFile(const string& filename,const string& messages)
{ofstream out(filename,ios::app);if(!out.is_open()){return;}out<<messages;out.close();
}
//等级转化为字符串
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 "Unkonwn";}
}//获取当前时间
string GetTimeString()
{time_t curr_time=time(nullptr);//时间戳struct tm* format_time=localtime(&curr_time);//转化为时间结构if(format_time==nullptr)return "None";char time_buffer[1024];snprintf(time_buffer,sizeof(time_buffer),"%d-%d-%d %d:%d:%d",format_time->tm_year + 1900,format_time->tm_mon + 1,format_time->tm_mday,format_time->tm_hour,format_time->tm_min,format_time->tm_sec);return time_buffer;}pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
//获取日志信息
void LogMessage(string filename,int line,bool issave,int level,char* format,...)
{string levelstr=LevelToString(level);string timestr=GetTimeString();pid_t selfid=getpid();char buffer[1024];va_list arg;va_start(arg,format);vsnprintf(buffer,sizeof(buffer),format,arg);va_end(arg);string message= "[" + timestr + "]" + "[" + levelstr + "]" +"[" + std::to_string(selfid) + "]" +"[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";LockGuard lockguard(&lock);if(!issave){cout<<message;}else{SaveFile(logname,message);}}#define LOG(level,format,...)                                               \do                                                                        \{                                                                          \LogMessage(__FILE__,__LINE__,gIsSave,level,format,##__VA_ARGS__);       \} while (0)#define EnableFile()         \do                       \{                        \gIsSave=true;        \  } while (0)#define EnableScreen()         \do                         \{                          \gIsSave=false;         \  } while (0)

线程池解释(代码)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

日志解释(代码)

日志是系统或程序记录所有发生事件的文件:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

Qt 统计图编程

学习目标&#xff1a;Qt 折线图&#xff0c;柱形图和扇形统计图编程 学习基础 Qt QChart 曲线图表操作-CSDN博客 学习内容 Qt中绘制三种常见的图表非常方便, 主要步骤如下: 1. 折线图: - 使用QLineSeries定义折线数据,添加多个坐标点 - 使用QValueAxis创建X轴和Y轴 - 将…

dockerfile配置和yml配置

dockerfile docker build 使用dockerfile自动构建镜像文件 FROM python:3.9WORKDIR /appCOPY requirements.txt. RUN pip install -r requirements.txtCOPY..CMD ["python", "main.py"]docker build dockerifle自动构建拉取python3.9镜像&#xff0c;并执…

拷贝文件的一些操作

利用fputc 、fgetc实现文件的拷贝 int main(int argc, const char *argv[]) {FILE* rfpfopen(argv[1],"r");FILE* wfpfopen(argv[2],"w");if(rfpNULL || wfpNULL){perror("fopen");return 1;}while(1){char resfgetc(rfp);if(feof(rfp)1){break;…

PointCloudLib LocalMaximum_DeleteMaxPoint C++版本

测试效果 简介 在点云库&#xff08;Point Cloud Library&#xff0c;PCL&#xff09;中&#xff0c;处理点云数据时&#xff0c;经常需要去除局部最大点&#xff08;Local Maximum&#xff09;&#xff0c;这通常用于去除噪声、提取特定形状的特征或者简化点云数据。局部最大…

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-14 SPI MASET发送程序设计

软件版本&#xff1a;Anlogic -TD5.9.1-DR1_ES1.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用安路(Anlogic)FPGA 实验平台&#xff1a;米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…

数据库管理-第220期 Oracle的高可用-03(20240715)

数据库管理220期 2024-07-15 数据库管理-第220期 Oracle的高可用-03&#xff08;20240715&#xff09;1 AC/TAC2 配置Service3 用户权限4 端口开放总结 数据库管理-第220期 Oracle的高可用-03&#xff08;20240715&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文…

Modbus - 笔记

1 Modbus Poll/Slave 模拟器使用教程 Modbus Poll/Slave 模拟器使用教程_modbus poll 使用教程-CSDN博客 https://item.jd.com/67488830087.html

Node.js 爬虫开发实战:构建一个高效、优雅的网络数据抓取器

在大数据时代&#xff0c;从网页上自动抓取数据的需求日益增长。Node.js&#xff0c;以其异步非阻塞I/O模型&#xff0c;成为了构建高性能网络爬虫的理想选择。本文将引导你如何使用Node.js&#xff0c;结合axios和cheerio两个流行库&#xff0c;创建一个能够从目标网站抓取信息…

51单片机10(蜂鸣器介绍)

一、蜂鸣器介绍&#xff1a; 1、蜂鸣器是一种一体化结构的电子讯响器&#xff0c;采用直流电压供电&#xff0c;广泛应用于电子产品中作为发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器。 &#xff08;1&#xff09;压电式蜂鸣器&#xff0c;它主要由多谐的一个增胀器…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(八)-通过无人机进行无线接入

引言 本文是3GPP TR 22.829 V17.1.0技术报告&#xff0c;专注于无人机&#xff08;UAV&#xff09;在3GPP系统中的增强支持。文章提出了多个无人机应用场景&#xff0c;分析了相应的能力要求&#xff0c;并建议了新的服务级别要求和关键性能指标&#xff08;KPIs&#xff09;。…

电脑出现错误——找不到msvcp140.dll无法继续执行代码,有效解决错误dll文件

msvcp140.dll是一个属于 Microsoft Visual C Redistributable for Visual Studio 2015 的 DLL 文件。这个文件是许多Windows应用程序&#xff08;尤其是使用 C 开发的程序&#xff09;所必需的&#xff0c;因为它包含了标准 C 库的函数实现&#xff0c;用于处理数学运算、数据转…

【React Hooks原理 - useRef】

概述 在Function Component项目中当我们需要操作dom的时候&#xff0c;第一时间想到的就是使用useRef这个Hook来绑定dom。但是这个仅仅是使用这个Hook而已&#xff0c;为了更好的学习React Hooks内部实现原理&#xff0c;知其所以然。所以本文根据源码从useRef的基础使用场景一…

使用shell脚本打印99乘法表

一、简介 前一段时间在旧电脑上安装 antiX 23.1 操作系统&#xff0c;遇到一些问题需要使用shell脚本解决问题&#xff0c;所以专门学习了几天&#xff0c;打印99乘法表是其中的一个练习作业。 二、学习Linux可行的几种方式 虚拟机安装Linux进行学习直接双系统安装在实体电脑…

Ubuntu新系统的使用

1.安装显卡驱动 直接到软件与更新里面&#xff0c;就是一个A字图标的那个软件打开&#xff0c;到附加驱动里选择。要选择“server driver”的&#xff0c;选择后确认即可。 然后输入&#xff1a;nvidia-sim查看 别的方法太复杂&#xff0c;这个方法我亲测了两台电脑&#xff…

kubebuilder入门

1. 安装kubebuilder brew install kubebuilder 2. 需求描述 开发一个zk operator。 cr定义为ZooKeeperCluster 3. 开发过程 3.1 创建一个空的文件夹zk-operator mkdir zk-operator 3.2 进入该文件夹 cd zk-operator 3.3 执行初始化 kubebuilder init --domain my.doma…

MWA(Modern Web App)初学那些事-2-Basic HTML CSS

初学MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS 目录 初学MWA(Modern Web App&#xff09;那些事-2-Basic HTML & CSS前言一、本节学习目标二、HTML基础内容2.1关键元素2.4 Scripts 三、CSS 基础内容3.1 级联样式表-用于设置网页样式和布局3.2 CSS规则语…

springcloud使用微服务的搭建

微服务的搭建 1.配置对应信息 Springboot 、springcloud、springcloud alibaba对应关系 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E 2.pom.xml的配置 2.1 总项目pom.xml引入依赖 <parent><groupId>org.sprin…

阿里通义音频生成大模型 FunAudioLLM 开源

简介 近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术的进步极大地改变了人类与机器的互动方式&#xff0c;特别是在语音处理领域。阿里巴巴通义实验室最近开源了一个名为FunAudioLLM的语音大模型项目&#xff0c;旨在促进人类与大型语言模型&#xff08;LLMs&…

vue3在 setup 中访问路由和当前路由

报错信息&#xff1a; Cannot read properties of undefined (reading $router) 原因&#xff1a; 因为我们在 setup 里面没有访问 this&#xff0c;所以我们不能直接访问 this.$router 或 this.$route。 解决方案&#xff1a; 作为替代&#xff0c;我们使用 useRouter 和…

Oracle字符集修改

提示 Oracle数据库默认的字符集编码为US7ASCII&#xff0c;这个编码是不支持中文的&#xff0c;如果想要在数据库存储中文&#xff0c;就需要修改编码为ZHS16GBK或UTF-8 编码和字符集是一个意思&#xff0c;只是叫法不一样而已 前置条件 修改字符集的前提是知道我们现在用的是什…