Linux|多线程(三)

线程池

线程池是一种多线程处理形式,处理过程中它将被提交的任务分配给预先创建好的多个线程中的一个去执行。

线程池的实现

#pragma once
#include <pthread.h>
#include <vector>
#include <string>
#include <unistd.h>
#include <pthread.h>
#include <queue>
#include <functional>
#include "task.hpp"
#include "thread.hpp"
using namespace ThreadModel;
// void test(const std::string &name)
// {

//     while (1)
//     {
//         std::cout << name << "is running.." << std::endl;
//         sleep(1);
//     }
// }
const int Default_nums = 3;

template <class T>
class ThreadPool
{
    using func_t = std::function<void(const std::string name)>;

private:
    bool isEmpty()
    {
        return _task_queue.size() == 0;
    }
    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }
    void lockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }
    void wakeUp()
    {
        pthread_cond_signal(&_cond);
    }
    void wakeUpAll()
    {
        pthread_cond_broadcast(&_cond);
    }

    void unlockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }
    void hadertask(const std::string name)
    {
        lockQueue();
        while (true)
        {
            while (isEmpty() && _isrunning)
            {
                _sleepnums++;
                std::cout << name << " star sleep" << std::endl;
                Sleep();
                std::cout << name << " awaken" << std::endl;
                _sleepnums--;
            }
            if (isEmpty() && !_isrunning)
            {
                unlockQueue();
                std::cout << name << " quit" << std::endl;
                break;
            }
            T t = _task_queue.front();
            _task_queue.pop();
            unlockQueue();
            t();
            std::cout << t.solve() << std::endl;
        }
    }
    void init()
    {
        // 并将调用func时的第一个参数传递给hander函数。
        func_t func = std::bind(&ThreadPool::hadertask, this, std::placeholders::_1);
        for (int i = 0; i < _thread_nums; i++)
        {

            std::string name = "thread-" + std::to_string(i + 1);

            _threads.emplace_back(name, func);
            std::cout << name << " init sucess" << std::endl;
        }
    }
    ThreadPool(int thread_nums = Default_nums) : _thread_nums(thread_nums), _sleepnums(0)
    {
        init();
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

public:
    ~ThreadPool()
    {
        pthread_cond_destroy(&_cond);
        pthread_mutex_destroy(&_mutex);
    }
    static ThreadPool<T> * GetInstance(int thread_nums = Default_nums)
    {
        if (_tp == nullptr)
        {
            pthread_mutex_lock(&_sig_mutx);
            if (_tp == nullptr)
            {
                _tp = new ThreadPool(thread_nums);
                std::cout<<"create instance"<<std::endl;
            }
            pthread_mutex_unlock(&_sig_mutx);
        }
        std::cout<<"get instance"<<std::endl;
        return _tp;
    }

    void start()
    {
        _isrunning = true;
        std::cout << "threadpool is running:" << std::endl;

        for (auto &thread : _threads) // 这个引用特别重要
        // 如果不传引用 thread 出了函数会被销毁 访问name 会出问题
        {

            thread.start();
        }
    }

    void equeue(const T &in)
    {
        // 拿数据和放数据要加锁 因为可能脏读
        lockQueue();
        if (_isrunning)
        {
            _task_queue.push(in);
            if (_sleepnums > 0)
            {
                wakeUp();
            }
        }

        std::cout << in.inquiry() << std::endl;

        unlockQueue();
    }
    void stop()
    {
        wakeUpAll();
        std::cout << "threadpool stop" << std::endl;
        _isrunning = false;
    }

private:
    std::queue<T> _task_queue;
    int _thread_nums;
    std::vector<Thread> _threads;
    bool _isrunning;
    int _sleepnums;

    pthread_mutex_t _mutex;
    pthread_cond_t _cond;

    static ThreadPool *_tp;
    static pthread_mutex_t _sig_mutx;
};
template <class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::_sig_mutx = PTHREAD_MUTEX_INITIALIZER;

日志类

#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <ctime>
#include <stdarg.h>
#include <fstream>
#include <cstring>
#include <pthread.h>
#include "lockerguard.hpp"
// namespace{}
namespace log_ns
{
#define SCREEN_TYPE 1
#define FILE_TYPE 2
    pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
    enum level
    {
        DEBUG = 1,
        INFO,
        WARNNING,
        ERROR,
        FATAL
    };
    std::string levelToString(int level)
    {
        switch (level)
        {
        case DEBUG:
            return "DEBUG";
        case INFO:
            return "INFO";
        case WARNNING:
            return "WARNNING";
        case ERROR:
            return "ERROR";
        case FATAL:
            return "FATAL";
        default:
            return "UNKNOW";
        }
    }
    std::string GetCurTime()
    {
        time_t now = time(nullptr);
        struct tm *cur_time = localtime(&now);
        char buff[128];
        snprintf(buff, 128, "%d-%02d-%02d %02d:%02d:%02d",
                 cur_time->tm_year + 1900,
                 cur_time->tm_mon + 1,
                 cur_time->tm_mday,
                 cur_time->tm_hour,
                 cur_time->tm_min,
                 cur_time->tm_sec);
        return buff;
    }
    class LogMessage
    {
    public:
        std::string _level;        // 日志等级
        pid_t _id;                 // 进程号
        std::string _filename;     // 文件名
        int _filenumber;           // 行号
        std::string _cur_time;     // 日志所写时间
        std::string _message_info; // 日志信息
    };
    const char *gfile = "./log.txt";
    class Log
    {
    public:
        Log(const std::string &logfile = gfile) : _logFile(logfile), _type(SCREEN_TYPE)
        {
        }
        void FlushLogToScreen(const LogMessage &lg)
        {
            printf("[%s][%d][%s][%d][%s] %s",
                   lg._level.c_str(),
                   lg._id,
                   lg._filename.c_str(),
                   lg._filenumber,
                   lg._cur_time.c_str(),
                   lg._message_info.c_str());
        }
        void FlushLogToFile(const LogMessage &lg)
        {
            //
            std::ofstream out(_logFile, std::ios::app);
            if (!out.is_open())
                return;
            char buff[1024];
            snprintf(buff, sizeof(buff), "[%s][%d][%s][%d][%s] %s",
                     lg._level.c_str(),
                     lg._id,
                     lg._filename.c_str(),
                     lg._filenumber,
                     lg._cur_time.c_str(),
                     lg._message_info.c_str());
            out.write(buff, strlen(buff));
            out.close();
        }
        void FlushLog(const LogMessage &lg)
        {
            LockGuard lockguard(&gmutex);
            switch (_type)
            {
            case SCREEN_TYPE:
                FlushLogToScreen(lg);
                break;
            case FILE_TYPE:
                FlushLogToFile(lg);
                break;
            default:
                break;
            }
        }
        void logMessage(int level, std::string filename, int filenumber, const char *format...)
        {
            LogMessage lg;
            lg._level = levelToString(level);
            lg._filename = filename;
            lg._filenumber = filenumber;
            lg._cur_time = GetCurTime();
            lg._id = getpid();
            va_list ap;
            va_start(ap, format);
            char buff[128];
            vsnprintf(buff, sizeof(buff), format, ap);
            va_end(ap);
            FlushLog(lg);
        }

    private:
        int _type;
        std::string _logFile;
    };
    Log lg;
#define LOG(Level, Format, ...)                                          \
    do                                                                   \
    {                                                                    \
        lg.logMessage(Level, __FILE__, __LINE__, Format, ##__VA_ARGS__); \
    } while (0)
#define EnableScreen()          \
    do                          \
    {                           \
        lg.Enable(SCREEN_TYPE); \
    } while (0)
#define EnableFile()          \
    do                        \
    {                         \
        lg.Enable(FILE_TYPE); \
    } while (0)
}

单例模式

 static ThreadPool<T> * GetInstance(int thread_nums = Default_nums)
    {
        if (_tp == nullptr)
        {
            pthread_mutex_lock(&_sig_mutx);
            if (_tp == nullptr)
            {
                _tp = new ThreadPool(thread_nums);
                std::cout<<"create instance"<<std::endl;
            }
            pthread_mutex_unlock(&_sig_mutx);
        }
        std::cout<<"get instance"<<std::endl;
        return _tp;
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值