胧の宝藏之地
首页项目归档照片墙音乐灵境说说杂谈友链关于
封面

线程池——单例模式

写作时间:2026-07-27 22:36:45

Mutex.hpp

#pragma once

#include<iostream>
#include<pthread.h>


class Mutex
{
public:
    Mutex()
    {
        pthread_mutex_init(&_lock , nullptr);
    }

    void Lock()
    {
        pthread_mutex_lock(&_lock);
    }

    pthread_mutex_t *Ptr()
    {
        return &_lock;
    }

    void Unlock()
    {
        pthread_mutex_unlock(&_lock);
    }

    ~Mutex()
    {
        pthread_mutex_destroy(&_lock);
    }
private:
    pthread_mutex_t _lock;
};

class LockGuard
{
public:
    LockGuard(Mutex &lock):_lockref(lock)
    {
        _lockref.Lock();
    }

    ~LockGuard()
    {
        _lockref.Unlock();
    }
private:
    Mutex &_lockref;
};

‍

Cond.hpp

#ifndef __COND_HPP
#define __COND_HPP

#include <pthread.h>
#include "Mutex.hpp"

class Cond
{
public:
    Cond()
    {
        pthread_cond_init(&_cond, nullptr);
    }
    void Wait(Mutex &mutex)
    {
        int n = pthread_cond_wait(&_cond, mutex.Ptr());
        (void)n;
    }
    void Signal()
    {
        int n = pthread_cond_signal(&_cond);
        (void)n;
    }
    void Broadcast()
    {
        int n = pthread_cond_broadcast(&_cond);
        (void)n;
    }
    ~Cond()
    {
        pthread_cond_destroy(&_cond);
    }
private:
    pthread_cond_t _cond;
};

#endif

Thread.hpp

#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <pthread.h>

namespace NS_THREAD_MODULE
{
    static int gnumber = 1;
    using callback_t = std::function<void()>;

    enum class TSTATUS
    {
        THREAD_NEW,
        THREAD_RUNNING,
        THREAD_STOP
    };

    std::string Status2String(TSTATUS s)
    {
        switch (s)
        {
        case TSTATUS::THREAD_NEW:
            return "THREAD_NEW";
        case TSTATUS::THREAD_RUNNING:
            return "THREAD_RUNNING";
        case TSTATUS::THREAD_STOP:
            return "THREAD_STOP";
        default:
            return "UNKNOWN";
        }
    }

    std::string IsJoined(bool joinable)
    {
        return joinable ? "true" : "false";
    }

    class Thread
    {
    private:
        void ToRunning()
        {
            _status = TSTATUS::THREAD_RUNNING;
        }
        void ToStop()
        {
            _status = TSTATUS::THREAD_STOP;
        }
        static void *ThreadRoutine(void *args)
        {
            Thread *self = static_cast<Thread *>(args);
            pthread_setname_np(self->_tid, self->_name.c_str());
            self->_cb();
            self->ToStop();
            return nullptr;
        }

    public:
        Thread(callback_t cb)
            : _tid(-1), _status(TSTATUS::THREAD_NEW), _joinable(true), _cb(cb), _result(nullptr)
        {
            _name = "New-Thread-" + std::to_string(gnumber++);
        }
        bool Start()
        {
            int n = pthread_create(&_tid, nullptr, ThreadRoutine, this);
            if (n != 0)
                return false;

            ToRunning();
            return true;
        }
        void Join()
        {
            if (_joinable)
            {
                int n = pthread_join(_tid, &_result);
                if (n != 0)
                {
                    std::cerr << "join error: " << n << std::endl;
                    return;
                }
                (void)_result;
                _status = TSTATUS::THREAD_STOP;
            }
            else
            {
                std::cerr << "error, thread join status: " << IsJoined(_joinable) << std::endl;
            }
        }
        // 暂停
        // void Stop() // restart()
        // {
        //     // 让线程暂停
        // }
        void Die()
        {
            if (_status == TSTATUS::THREAD_RUNNING)
            {
                pthread_cancel(_tid);
                _status = TSTATUS::THREAD_STOP;
            }
        }
        void Detach()
        {
            if (_status == TSTATUS::THREAD_RUNNING && _joinable)
            {
                pthread_detach(_tid);
                _joinable = false;
            }
            else
            {
                std::cerr << "detach " << _name << " failed" << std::endl;
            }
        }
        void PrintInfo()
        {
            std::cout << "thread name : " << _name << std::endl;
            std::cout << "thread _tid : " << _tid << std::endl;
            std::cout << "thread _status : " << Status2String(_status) << std::endl;
            std::cout << "thread _joinable : " << IsJoined(_joinable) << std::endl;
        }

        ~Thread()
        {
        }

    private:
        std::string _name;
        pthread_t _tid;
        TSTATUS _status;
        bool _joinable;
        // 线程要有自己的任务处理,即回调函数
        callback_t _cb;

        // 线程退出信息
        void *_result;
    };
}

Logger.hpp

#ifndef __LOGGER_HPP
#define __LOGGER_HPP

#include<iostream>
#include<cstdio>
#include<string>
#include<memory> 
#include<sstream>
#include<ctime>
#include<sys/time.h>
#include<unistd.h>
#include<filesystem>
#include<sys/stat.h>
#include<fstream>
#include"Mutex.hpp"

namespace NS_LOG_MODULE
{
    enum class LogLevel
    {
        INFO,
        WARNING,
        ERROR,
        FATAL,
        DEBUG
    };

    std::string LogLevel2Message(LogLevel level)
    {
        switch(level)
        {
            case LogLevel::INFO:
                    return "INFO";
            case LogLevel::WARNING:
                    return "WARNING";
            case LogLevel::ERROR:
                    return "ERROR";
            case LogLevel::FATAL:
                    return "FATAL";
            case LogLevel::DEBUG:
                    return "DEBUG";
            default:
                    return "UNKNOWN";
        }
    }

    std::string GetCurrentTime()
    {
        struct timeval current_time;
        int n = gettimeofday(&current_time , nullptr);
        (void)n;

        struct tm struct_time;
        localtime_r(&(current_time.tv_sec) , &struct_time);

        char timestr[128];
        snprintf(timestr , sizeof(timestr) , "%04d-%02d-%02d %02d:%02d:%02d.%ld" , 
                struct_time.tm_year + 1900,
                struct_time.tm_mon + 1,
                struct_time.tm_mday,
                struct_time.tm_hour,
                struct_time.tm_min,
                struct_time.tm_sec,
                current_time.tv_usec);
        return timestr;
    }

    // 策略模式,策略接口
    // 1. 显示器打印
    // 2. 文件写入
    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default;
        virtual void SyncLog(const std::string &message) = 0;

    };

    // 控制台日志刷新策略, 日志将来要向显示器打印
    class ConsoleStartegy : public LogStrategy 
    {
    public:
        void SyncLog(const std::string &message) override
        {
            LockGuard lockguard(_mutex);
            std::cerr <<message <<"\n";
        } 

        ~ConsoleStartegy()
        {}

    private:
        Mutex _mutex;
    };


    const std::string defaultpath = "./log";
    const std::string defaultname = "log.txt";

    // 文件策略
    class FileLogStrategy :public LogStrategy
    {
    public:
        FileLogStrategy(const std::string &path = defaultpath , const std::string &name = defaultname):
                        _logpath(path),
                        _logfilename(name)
        {
            if(std::filesystem::exists(_logpath))
                return;
            try
            {
                std::filesystem::create_directories(_logpath);
            }
            catch(const std::filesystem::filesystem_error &e)
            {
                std::cerr<<e.what() <<"\n";
            }

        }


        void SyncLog(const std::string &message) override
        {
            LockGuard lockguard(_mutex);
            if(!_logpath.empty() && _logpath.back() !='/')
            {
                _logpath += "/";
            }
            std::string targetlog = _logpath + _logfilename;
            std::ofstream out(targetlog , std::ios::app); // 追加写入
            if(!out.is_open())
            {
                std::cerr<<"open" <<targetlog <<"failen" <<std::endl;
                return;
            }
            out << message << "\n";
            out.close();
        }

        ~FileLogStrategy()
        {}

    private:
        std::string _logpath;
        std::string _logfilename;
        Mutex _mutex;
    };

    class Logger
    {
        // 日志生成



    public:
        Logger()
        {
            UseConsoleStrategy();
        }

        void UseConsoleStrategy()
        {
            _strategy = std::make_unique<ConsoleStartegy>();
        }

        void UseFileStrategy()
        {
            _strategy = std::make_unique<FileLogStrategy>();
        }

        // void Debug(const std::string &message)
        // {
        //     if(_strategy != nullptr)
        //     {
        //         _strategy->SyncLog(message);
        //     }
        // }

        class LogMessage
        {
        public:
            LogMessage(LogLevel level , std::string &filename , int line , Logger &logger):
            _level(level),
            _curr_time(GetCurrentTime()),
            _pid(getpid()),
            _filename(filename),
            _line(line),
            _logger(logger)
            {
                std::stringstream ss;
                ss  <<"[" <<_curr_time <<"] " 
                    <<"[" <<LogLevel2Message(_level) <<"] "
                    <<"[" <<_pid <<"] " 
                    <<"[" <<_filename <<"] "
                    <<"[" <<_line <<"] "
                    <<" : ";    

                    _loginfo = ss.str();
            }

            template<typename T>
            LogMessage &operator << (const T &info)
            {
                std::stringstream ss;
                ss <<info;
                _loginfo += ss.str();
                return *this; // 返回当前LogMessage对象
            }

            ~LogMessage()
            {
                if(_logger._strategy)
                {
                    _logger._strategy->SyncLog(_loginfo);
                }
            }

        private:
            LogLevel _level;
            std::string _curr_time;
            pid_t _pid;
            std::string _filename;
            int _line;
            std::string _loginfo;
            Logger &_logger;
        };

        LogMessage operator()(LogLevel level , std::string filename , int line)
        {
            return LogMessage(level , filename , line , *this);
        }

        ~Logger()
        {}

    private:
        std::unique_ptr<LogStrategy> _strategy;  // 刷新策略
    };

Logger logger;

#define ENABLE_CONSOLE_LOG_STRATEGY() logger.UseConsoleStrategy();
#define ENABLE_FILE_LOG_STRATEGY() logger.UseFileStrategy();


#define LOG(level) logger(level , __FILE__ , __LINE__)


}
#endif

ThreadPool.hpp

#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include "Logger.hpp"
#include "Thread.hpp"
#include "Cond.hpp"

namespace NS_THREAD_POOL
{
    using namespace NS_LOG_MODULE;
    using namespace NS_THREAD_MODULE;

    const int defaultnum = 5;

    // void Test()
    // {
    //     char name[128];
    //     pthread_getname_np(pthread_self(), name, sizeof(name));
    //     while ((true))
    //     {
    //         LOG(LogLevel::DEBUG) << "运行线程" << name;
    //         sleep(1);
    //     }
    // }

    template <typename T>
    class ThreadPool
    {
    private:
        void HendlerTask()
        {
            char name[128];
            pthread_getname_np(pthread_self(), name, sizeof(name));
            while ((true))
            {
                T task;
                {
                    LockGuard lockguard(_mutex);

                    while (_tasks.empty() && _isrunning)
                    {
                        _slaver_sleeper_count++;
                        _cond.Wait(_mutex);
                        _slaver_sleeper_count--;
                    }

                    if (!_isrunning && _tasks.empty())
                    {
                        _mutex.Unlock();
                        break;
                    }

                    task = _tasks.front();
                    _tasks.pop();
                }
                LOG(LogLevel::INFO) << name << "处理任务:";
                task();
                LOG(LogLevel::DEBUG) << task.Result();
            }
            LOG(LogLevel::INFO) << name << "quit...";
        }

        ThreadPool(int slaver_num = defaultnum) : _isrunning(false), _slaver_sleeper_count(0), _slaver_num(slaver_num)
        {
            for (int idx = 0; idx < _slaver_num; idx++)
            {
                // auto f = std::bind(&ThreadPool::HendlerTask , this);
                // auto f = [this](){
                //     this->HendlerTask();
                // };
                // _slavers.emplace_back(f);

                _slavers.emplace_back([this]()
                                      { this->HendlerTask(); });
            }
        }

        // 赋值 拷贝构造禁止
        ThreadPool<T> &operator=(const ThreadPool<T> &) = delete;
        ThreadPool(const ThreadPool<T> &) = delete;

    public:
        static ThreadPool<T> *Instance()
        {
            if(nullptr == _instance)
            {
                LockGuard lockguard(_lock);
                if (nullptr == _instance)
                {
                    _instance = new ThreadPool<T>();
                    _instance->Start();
                    LOG(LogLevel::INFO) << "创建线程池对象";
                }
            }
            return _instance;
        }
        void Start()
        {
            if (_isrunning)
            {
                LOG(LogLevel::WARNING) << "Thread Pool Is Already Running";
                return;
            }
            _isrunning = true;
            for (auto &slave : _slavers)
            {
                slave.Start();
            }
        }

        void Stop()
        {
            _mutex.Lock();
            _isrunning = false;
            if (_slaver_sleeper_count > 0)
                _cond.Broadcast();
            _mutex.Unlock();
        }

        void Wait()
        {
            for (auto &slave : _slavers)
            {
                slave.Join();
            }
        }

        void EnQueue(T in)
        {
            _mutex.Lock();
            _tasks.push(in);
            if (_slaver_sleeper_count > 0)
                _cond.Signal();
            _mutex.Unlock();
        }

        ~ThreadPool()
        {
        }

    private:
        bool _isrunning;
        int _slaver_num;
        std::vector<Thread> _slavers;
        std::queue<T> _tasks;
        Mutex _mutex;
        Cond _cond;
        int _slaver_sleeper_count;

        static ThreadPool<T> *_instance;
        static Mutex _lock;
    };

    template <typename T>
    ThreadPool<T> *ThreadPool<T>::_instance = nullptr;

    template <typename T>
    Mutex ThreadPool<T>::_lock;
}

Main.cc

#include"Logger.hpp"
#include"ThreadPool.hpp"

#include<iostream>
#include<memory>
#include<functional>
#include<ctime>
#include<cstdlib>

using namespace NS_LOG_MODULE;
using namespace NS_THREAD_POOL;

using task_t = std::function<void()>;

class Task
{
public:
    Task(){}
    Task(int x , int y): _x(x) , _y(y)
    {}

    void operator()()
    {
        _result = _x + _y;
    }

    std::string Result()
    {
        return std::to_string(_x) + " + " + std::to_string(_y) +" = " + std::to_string(_result);
    }

    ~Task(){}

private:
    int _x;
    int _y;
    int _result;
};

int main()
{

    ENABLE_CONSOLE_LOG_STRATEGY();
    srand((long)time(nullptr) ^ getpid());
    int cnt = 10;

    sleep(5);

    while(cnt--)
    {
        int x = rand() % 11 + 1;
        usleep(337);
        int y = rand() % 13 + 1;
        Task t(x , y);
        ThreadPool<Task>::Instance()->EnQueue(t);
        sleep(1);
    }

    ThreadPool<Task>::Instance()->Stop();
    ThreadPool<Task>::Instance()->Wait();

    return 0;
}

Makefile

threadpool:Main.cc
	g++ -o $@ $^ -std=c++17 -g
.PHONY:clean
clean:
	rm -f threadpool

‍

avatar

胧

RECOMMENDED

线程控制

2026-07-21 01:47:21

进程控制

2026-07-11 20:27:31

线程封装

2026-07-23 13:49:45

Table of Contents