LINUX:懒汉单例模式线程池

目录

1.什么是线程池,线程池的优势

2.懒汉和饿汉模式

3.单例模式

4.日志系统

5.线程池


1.什么是线程池,线程池的优势

创建一个线程,就是要这个线程去完成某种任务的。

池化技术就是,提前创建一批线程,有任务这一批线程就会执行。而不是有任务的时候在去创建线程。

池化技术有着更高的效率,因为线程都是提前创建好的,直接执行任务。

2.懒汉和饿汉模式

懒汉和饿汉模式是一种设计模式

懒汉模式:

例:进程需要一块内存资源,什么时候真正用到了这块内存时,我在去创建而不是提前创建。

这种模式的优点就是,启动的更快,程序启动时,数据要加载到内存,懒汉就是延时加载,用的时候在加载。

3.单例模式

就是某一些类,就应该只有一个对象,不应该有多个。

线程池就是这样的,创建两个线程池也没有意义,可以多创建几个线程。

实现方法

将类的构造函数进行私有,这样就无法在创建对象了。

在类中提供一个共有的静态方法,这个方法可以初始化和获取线程池。

4.日志系统

这个没什么难度,就是字符串的拼接,可能需要注意的就是可变参数的使用。

log.hpp

cpp 复制代码
#ifndef __LOG_HPP__
#define __LOG_HPP__
#include <iostream>
#include <string>
#include <time.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdarg.h>
#include <fstream>
// 日志等级
 enum loglevel
    {
        Debug = 0,
        Info,
        Warning,
        Error,
        FATAL,
    };
namespace lg
{
    bool isSave = false; //是否保存到文件
   
    std::string savefile = "log.txt";//保存的文件名
   
    
    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 "Unknown";
        }
    }

    std::string TimetoString() //将时间转化为字符串
    {
        time_t cur_time = time(nullptr);
        tm *formattime = localtime(&cur_time);
        return std::string(std::to_string(formattime->tm_year + 1900) + "/" + std::to_string(formattime->tm_mon + 1) + "/" + std::to_string(formattime->tm_mday) + " " + std::to_string(formattime->tm_hour + 1) + ":" + std::to_string(formattime->tm_min + 1));
    }

    std::string PidtoString()//将pid转化为字符串
    {
        return std::to_string(getpid());
    }

    void SavetoFile(std::string &message)//保存到文件
    {
        std::ofstream out(savefile, std::ios::app);
        if (!out.is_open())
        {
            return;
        }
        out << message << std::endl;
        out.close();
    }

    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    // 日志的格式: 日志等级 + 日志时间 + 代码文件名 + 行数 + 日志内容
    void LogMessage(std::string filename, int linenum, int level, const char *formate, ...)
    {
        std::string levelstring = LeveltoString(level);

        std::string timestring = TimetoString();

        std::string pidstring = PidtoString();

        //是对可变参数的解析
        char buffer[1024];
        va_list ap;
        va_start(ap, formate);
        vsnprintf(buffer, sizeof(buffer), formate, ap);
        va_end(ap);

        std::string contentstring = move(std::string(buffer));

        std::string message = "[" + levelstring + "]" + "[" + timestring + "]" + "[" + filename + "]" + "[" + std::to_string(linenum) + "]" + "[" + pidstring + "]" + "[" + contentstring + "]";
        if (!isSave)
        {
            pthread_mutex_lock(&mutex);
            std::cout << message << std::endl;
            pthread_mutex_unlock(&mutex);
        }
        else
        {
            SavetoFile(message);
        }
    }

#define Log(level, format, ...)                                                \
    do                                                                         \
    {                                                                          \
        LogMessage(__FILE__, __LINE__, level, format, ##__VA_ARGS__); \
    } while (0)

#define save()         \
    do                 \
    {                  \
        isSave = true; \
    } while (0);

#define print()        \
    do                 \
    {                  \
        isSave = false; \
    } while (0);
}


#endif

5.线程池

threadpool.hpp

cpp 复制代码
#ifndef __THREADPOOL__
#define __THREADPOOL__

#include <iostream>
#include <pthread.h>
#include <thread>
#include <unistd.h>
#include <queue>
#include <semaphore.h>
#include "log.hpp"
#include <functional>

// 创建出一批线程,从任务队列里拿任务


namespace mtp
{
    using namespace lg;
    using namespace std::placeholders;
    int _default = 3;
    template <class T>
    class threadpool
    {
    private:
        threadpool(int threadnum = _default)
            : _threadnum(threadnum)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_cond_init(&_cond, nullptr);
            Log(Info, "Construct threadpool");
        }

        // 线程的回调方法
        void handlertask(std::string name)
        {
            while (true)
            {
                pthread_mutex_lock(&_mutex);
                // 线程池运行 任务队列为空时
                while (_isrunning && _taskqueue.empty())
                {
                    _waitnum++;
                    pthread_cond_wait(&_cond, &_mutex);
                    _waitnum--;
                }
                // 线程池不运行 任务队列为空
                if (!_isrunning && _taskqueue.empty())
                {
                    pthread_mutex_unlock(&_mutex);
                    break;
                }
                // 线程池运行 队列不为空
                // 线程池不运行 队列不为空
                T t = _taskqueue.front();
                _taskqueue.pop();
                pthread_mutex_unlock(&_mutex);
                t(name); // 执行任务
                // std::cout<<"handler" << t <<std::endl;
            }
        }

        // 创建线程
        void Init()
        {
            for (int i = 0; i < _threadnum; i++)
            {
                std::string name = "thread" + std::to_string(i);
                _threads.emplace_back(std::bind(&threadpool::handlertask, this, _1), name);
                Log(Info, "create %s", name.c_str());
            }
        }

        ~threadpool()
        {
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_cond);
            Log(Info, "threadpool destory");
        }
        // 禁止拷贝
        threadpool<T> &operator=(const threadpool<T> &) = delete;
        threadpool(const threadpool<T> &) = delete;

    public:
    
        // 执行单例模式
        static threadpool<T>* getInstance()
        {
            if (_instance == nullptr)//加上这个if语句,如果是获取线程池,就不用获取锁了
            {
                // 初始化线程池
                pthread_mutex_lock(&_lock);
                //只有第一次线程创建时才会进,无论创建还是获取都要返回 一个线程池的指针
                if (_instance == nullptr)
                {
                    _instance = new threadpool<T>;
                    _instance->Init();
                    Log(Info, "Init threadpool");
                }
                pthread_mutex_unlock(&_lock);
            }
            Log(Info, "get threadpool");
            return _instance;
        }

        
        void stop()
        {
            pthread_mutex_lock(&_mutex);
            _isrunning = false;
            pthread_mutex_unlock(&_mutex);
            pthread_cond_broadcast(&_cond);
        }

        void waitall()
        {
            for (auto &thread : _threads)
            {
                thread.join();
            }
            Log(Info, "Wait Sucess");
        }

        void enqueue(T t)
        {
            pthread_mutex_lock(&_mutex);
            if (_isrunning)
            {
                _taskqueue.push(t);
                Log(Info, "push task sucess");
                if (_waitnum > 0)
                {
                    pthread_cond_signal(&_cond);
                }
            }
            pthread_mutex_unlock(&_mutex);
        }

    private:
        int _threadnum;
        std::vector<std::thread> _threads;
        std::queue<T> _taskqueue; // 任务队列
        pthread_mutex_t _mutex;
        pthread_cond_t _cond;
        bool _isrunning = true; // 是否运行
        int _waitnum = 0;       // d等待的线程数

        // 添加单例模式
        static threadpool<T> *_instance;
        static pthread_mutex_t _lock; // 为了保证单例模式的线程安全
    };

    template <class T>
    threadpool<T> *threadpool<T>::_instance = nullptr;
    template <class T>
    pthread_mutex_t threadpool<T>::_lock = PTHREAD_MUTEX_INITIALIZER;
}

#endif

Task.hpp

cpp 复制代码
#ifndef __task_HPP__
#define __task_HPP__

#include<string>
#include<stdlib.h>
#include<time.h>
#include<iostream>
class Task
{
public:
Task(std::string taskname)
:_taskname(taskname)
{}

void operator()(std::string name)
{
    sleep(1);
    std::cout << name <<"Excute "<< _taskname << std::endl;
}


private:
    std::string _taskname;
};



#endif
相关推荐
6.944 分钟前
Scala学习记录 递归调用 练习
开发语言·学习·scala
Aileen_0v014 分钟前
【AI驱动的数据结构:包装类的艺术与科学】
linux·数据结构·人工智能·笔记·网络协议·tcp/ip·whisper
FF在路上26 分钟前
Knife4j调试实体类传参扁平化模式修改:default-flat-param-object: true
java·开发语言
州周1 小时前
Ftp目录整个下载
linux·服务器·数据库
Jackey_Song_Odd1 小时前
Ubuntu 24.04.1 解决部分中文字符(门、径)显示错误的问题
linux·ubuntu
kaixin_learn_qt_ing1 小时前
Linux export命令
linux
余额不足121381 小时前
C语言基础十六:枚举、c语言中文件的读写操作
linux·c语言·算法
众拾达人1 小时前
Android自动化测试实战 Java篇 主流工具 框架 脚本
android·java·开发语言
皓木.1 小时前
Mybatis-Plus
java·开发语言
不良人天码星1 小时前
lombok插件不生效
java·开发语言·intellij-idea