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;//存储线程的vector
    queue<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)
    

线程池解释(代码)

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

日志解释(代码)

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS实现超链接标签:鼠标光标为手形、取消下划线、当鼠标悬停时显示下划线

1、鼠标光标为手形 cursor: pointer; 2、显示/取消下划线 text-decoration: none; /* 文本取消下划线 */ text-decoration: underline; /* 文本添加下划线 */ 3、伪类选择器 伪类选择器是 CSS 中已经定义好的选择器&#xff0c;因此程序员不能随意命令。伪类选择器…

【BUG】已解决:ModuleNotFoundError: No module named ‘cv2’

已解决&#xff1a;ModuleNotFoundError: No module named ‘cv2’ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开…

C 语言指针进阶

1.0 指针的定义 指针是内存中一个最小单元的编号&#xff08;内存单元的编号称之为地址【地址就是指针指针就是地址】&#xff09;指针通常是用来存放内存地址的一个变量。本质上指针就是地址&#xff1a;口语上说的指针起始是指针变量&#xff0c;指针变量就是一个变量&#…

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

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

JVM--自动内存管理--JAVA内存区域

1. 运行时数据区域 灰色的线程共享&#xff0c;白色的线程独享 白色的独享就是根据个体"同生共死" 程序计数器&#xff1a; 是唯一一个没有OOM(内存溢出)的地方 是线程独享的 作用&#xff1a; 是一块较小的内存空间,是当前线程所执行的字节吗的行号指示器 由于…

C#学习3-微软C#官方文档Microsoft-dotnet-csharp.pdf

文章目录 1.内插表达式的字段宽度和对齐方式 1.内插表达式的字段宽度和对齐方式 static void Main(string[] args) {var titles new Dictionary<string, string>() {["Doyle ,Arthur"] "Hound of the Basker,The",["Lodon ,Jack"] &quo…

vue router 切换路由的时候,页面的动画效果,使页面切换好看,以及控制有的页面使用切换路由特效,有的页面不用

一、使用切换效果 在router文件中 useTransition: true代表需要动画 meta: { title: “新开卡预填表单”, keepAlive: true, useTransition: true }, [{path: "/",name: "Home",meta: {title: "首页",keepAlive: true,useTransition: false},c…

Python 给存入 Redis 的键值对设置过期时间

Redis 是一种内存中的数据存储系统&#xff0c;与许多传统数据库相比&#xff0c;它具有一些优势&#xff0c;其中之一就是可以设置数据的过期时间。通过 Redis 的过期时间设置&#xff0c;可以为存储在 Redis 中的数据设置一个特定的生存时间。一旦数据到达过期时间&#xff0…

alike-cpp 编译

1. 源码链接&#xff1a; https://github.com/Shiaoming/ALIKE-cpp 2.已经安装好显卡驱动&#xff0c;cuda&#xff0c;cudnn,没安装的参考&#xff1a; 切记装cuda-11.x的版本&#xff0c;最好cuda11.3的版本 ubuntu重装系统后&#xff0c;安装cuda,cudnn-CSDN博客 3.安装…

【学习笔记】无人机(UAV)在3GPP系统中的增强支持(十三)-更换无人机控制器

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

vitest 单元测试应用与配置

vitest 应用与配置 一、简介 Vitest 旨在将自己定位为 Vite 项目的首选测试框架&#xff0c;即使对于不使用 Vite 的项目也是一个可靠的替代方案。它本身也兼容一些Jest的API用法。 二、安装vitest // npm npm install -D vitest // yarn yarn add -D vitest // pnpm pnpm …

应用实践之基于MindNLP+MusicGen生成自己的个性化音乐

前言 MusicGen是基于单个语言模型&#xff08;LM&#xff09;的音乐生成模型&#xff0c;使用文本描述或音频提示生成高质量的音乐样本。它基于Transformer结构&#xff0c;包括文本编码器模型和音频压缩模型&#xff0c;以及一个解码器来预测离散的隐形状态音频token。与传统…

《mysql篇》--JDBC编程

JDBC是什么 JDBC就是Java DataBase Connectivity的缩写&#xff0c;翻译过来就很好理解了&#xff0c;就是java连接数据库。所以顾名思义&#xff0c;JDBC就是一种用于执行SQL语句的JavaApl&#xff0c;是Java中的数据库连接规范。为了可以方便的用Java连接各种数据库&#xff…

WSL2 的安装与运行 Linux 系统

前言 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能&#xff0c;允许开发人员在 Windows 系统上直接安装并使用 Linux 发行版。不用进行任何修改&#xff0c;也无需承担传统虚拟机或双启动设置的开销。 可以将 WSL 看作也是一个虚拟机&#xff0c;但是它更为便…

Contact Form联系表单自动发送邮件(超级简单)

前几天发现了aoksend推出的这个联系表单的组件&#xff0c;非常好用&#xff0c;只有一个php文件&#xff0c;把php文件放到网站主目录里面。然后去aoksend注册和配置好域名和发信邮箱&#xff0c;可以得到发送密钥&#xff1a;app_key&#xff0c;然后配置好邮件模板&#xff…

线程安全(二)synchronized 的底层实现原理、锁升级、对象的内存结构

目录 一、基础使用1.1 不加锁的代码实现1.2 加锁的代码实现二、实现原理2.1 synchronized 简介2.2 对象监控器(Monitor)2.3 加锁过程第一步:判断 Owner 指向第二步:进入 EntryList 阻塞第三步:主动进入 WaitSet 等待三、锁升级3.1 对象的内存结构3.2 Mark Word 对象头3.3 …

全方位指南,电子期刊制作入门到精通

在这个数字化时代&#xff0c;电子期刊作为一种新兴的媒体形式&#xff0c;以其方便快捷、互动性强、传播范围广等特点&#xff0c;受到越来越多人的青睐。那么&#xff0c;如何制作出一本既专业又有吸引力的电子期刊呢&#xff1f; 一、选择合适的制作软件 首先&#xff0c;选…

Docker 使用基础(7)—Dockerfile

​ &#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;秒針を噛む—ずっと真夜中でいいのに。 0:34━━━━━━️&#x1f49f;──────── 4:20 &#x1f504; ◀️ ⏸…

Pod网络、Service网络、网络插件Calico、网络插件Flannel(2024-07-12)

一、Pod网络 在K8S集群里&#xff0c;多个节点上的Pod相互通信&#xff0c;要通过网络插件来完成&#xff0c;比如Calico网络插件。 使用kubeadm初始化K8S集群时&#xff0c;有指定一个参数 --pod-networkcidr10.18.0.0/16 它用来定义Pod的网段。而我们在配置Calico的时候&…

视频号矩阵系统源码,实现AI自动生成文案和自动回复私信评论,支持多个短视频平台

在当今短视频蓬勃发展的时代&#xff0c;视频号矩阵系统源码成为了自媒体人争相探索的宝藏。这一强大的技术工具不仅能帮助我们高效管理多个短视频平台&#xff0c;更能通过AI智能生成文案和自动回复私信评论&#xff0c;为自媒体运营带来前所未有的便利与效率。 一、视频号矩…