创建线程池和封装锁

封装一个锁

1.封装一个Mutex

cpp 复制代码
class Mutex{
    public:
    Mutex(pthread_mutex_t * lock):_lock(lock)
    {}
    void Lock()
    {
        pthread_mutex_lock(_lock);
    }
     void unLock()
    {
        pthread_mutex_unlock(_lock);
    }
    ~Mutex()
    {}
    private:
    pthread_mutex_t *_lock;
};

2.封装一个LockGuard

cpp 复制代码
class LockGuard{
    public:
    LockGuard(pthread_mutex_t * lock):_mutex(lock)
    {
        _mutex.Lock();
    }
    ~LockGuard()
    {
        _mutex.unLock();
    }
    private:
    Mutex _mutex;
};

在底层就可以直接创建一个LockGuard对象,就可以直接对临时资源进行加锁

类似:

cpp 复制代码
​
{

LockGuard(&mutex);

//临界资源

}

​

创建线程池

封装线程

1.成员变量

cpp 复制代码
private:
    std::string _threadname;
    pthread_t _pid;
    func_t<T> _func;
    bool _isrunning;
    T _data;
cpp 复制代码
template <class T>
using func_t = std::function<void(T&)>;

我们创建一个fun_t 用来传递一个函数给线程,在内部用来回调。

2.构造函数

cpp 复制代码
  Thread(std::string threadname, func_t<T> func, T& data)
        : _threadname(threadname), _pid(0), _func(func), _isrunning(false), _data(data)
    {
       
    }

3.Start函数和Join函数

cpp 复制代码
 bool Start()
    {
        
        int n = pthread_create(&_pid, nullptr, ThreadRoutine, this);
        if (n == 0)
        {
            _isrunning = true;
            return true;
        }
        return false;
    }
    bool Join()
    {
        if(!_isrunning) return true;
        int n=pthread_join(_pid,nullptr);
        if(n==0)
        {
            _isrunning=false;
            return true;
        }
        else
        {
            return false;
        }
    }

4.在创建线程传递一个ThreadRoution函数

cpp 复制代码
static void *ThreadRoutine(void *args) // 类内方法,
    {
        // (void)args; // 仅仅是为了防止编译器有告警
        Thread *ts = static_cast<Thread *>(args);

        ts->_func(ts->_data);

        return nullptr;
    }

ThreadRountion可不可以为类内函数?

不可以,类内函数默认隐藏的传递this指针,我们必须设置为静态函数函数,再传递this指针。

cpp 复制代码
#pragma once

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

template <class T>
using func_t = std::function<void(T&)>;

template <class T>
class Thread
{
public:
    Thread(std::string threadname, func_t<T> func, T& data)
        : _threadname(threadname), _pid(0), _func(func), _isrunning(false), _data(data)
    {
       
    }
    static void *ThreadRoutine(void *args) // 类内方法,
    {
        // (void)args; // 仅仅是为了防止编译器有告警
        Thread *ts = static_cast<Thread *>(args);

        ts->_func(ts->_data);

        return nullptr;
    }
    bool Start()
    {
        
        int n = pthread_create(&_pid, nullptr, ThreadRoutine, this);
        if (n == 0)
        {
            _isrunning = true;
            return true;
        }
        return false;
    }
    bool Join()
    {
        if(!_isrunning) return true;
        int n=pthread_join(_pid,nullptr);
        if(n==0)
        {
            _isrunning=false;
            return true;
        }
        else
        {
            return false;
        }
    }
    const std::string& Threadname()
    {
        return _threadname;
    } 

private:
    std::string _threadname;
    pthread_t _pid;
    func_t<T> _func;
    bool _isrunning;
    T _data;
};

创建线程池

我们打算用queue来储存任务,用vector数组储存线程

当任务队列为空时,我们用条件变量去控制线程睡眠,队列Push进任务再控制线程醒来。

1.成员变量

cpp 复制代码
private:
    queue<T> _taskq;
    vector<Thread<ThreadData>> _ptdv;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    int _thread_num;

2.构造函数

初始化锁,条件变量,并创建线程。

cpp 复制代码
  pthread_pool(int thread_num = defaultthreadnum) : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 1; i <= defaultthreadnum; i++)
        {

            string threadname("thread-");
            threadname += to_string(i);
            ThreadData td(threadname);
            Thread<ThreadData> t(threadname,
                                 std::bind(&pthread_pool<T>::pthread_Run, this, std::placeholders::_1), td);

            _ptdv.push_back(t);
            lg.LogMessage(Info, "%s is created...\n", threadname.c_str());
        }
    }

任务队列为空,让所有线程休眠,队列中有任务,直接让线程执行任务:t()

cpp 复制代码
void pthread_Run(ThreadData &data)
    {
        while (true)
        {
            T t;
            {
                LockGuard ld(&_mutex);
                if (_taskq.empty())
                {
                    allthreadsleep(data);
                }
                t = _taskq.front();

                _taskq.pop();
            }

            t();
            {
                LockGuard ld(&_mutex);
                lg.LogMessage(Info, "Thread name:%s is handling: %s \n", data._name.c_str(), t.PrintTask().c_str());
                lg.LogMessage(Info, "Thread name:%s get result: %s \n", data._name.c_str(), t.PrintResult().c_str());
            }
        }
    }

3.进程唤醒与进程休眠

cpp 复制代码
void allthreadwakeup()
    {
        pthread_cond_signal(&_cond);
    }
void allthreadsleep(const ThreadData &data)
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", data._name.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }

4.Push()

cpp 复制代码
    void Push(T &task)
    {

        {
            LockGuard ld(&_mutex);

            _taskq.push(task);

            // 插入任务后唤醒进程
            allthreadwakeup();
        }
    }
cpp 复制代码
#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <cstring>
#include <functional>
#include <unistd.h>
#include "pthread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"
using namespace std;
static const int defaultthreadnum = 5;

template <class T>
using func_r = std::function<void(T)>;

class ThreadData
{
public:
    ThreadData(string name) : _name(name)
    {
    }
    ~ThreadData()
    {
    }

public:
    string _name;
};
template <class T>
class pthread_pool
{
public:
    static pthread_pool<T> *Getinstance()
    {
        if (instance == nullptr)
        {
            pthread_mutex_lock(&_sig_ins);
            if (instance == nullptr)
            {
                instance = new pthread_pool<T>(defaultthreadnum);
                lg.LogMessage(Info, "instance is create succeess...\n");
                return instance;
            }
            
        }
        
    }

    pthread_pool(int thread_num = defaultthreadnum) : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for (int i = 1; i <= defaultthreadnum; i++)
        {

            string threadname("thread-");
            threadname += to_string(i);
            ThreadData td(threadname);
            Thread<ThreadData> t(threadname,
                                 std::bind(&pthread_pool<T>::pthread_Run, this, std::placeholders::_1), td);

            _ptdv.push_back(t);
            lg.LogMessage(Info, "%s is created...\n", threadname.c_str());
        }
    }
    pthread_pool(const pthread_pool<T> &pp) = delete;
    const pthread_pool<T> &operator=(const pthread_pool<T> &pp) = delete;
    void allthreadwakeup()
    {
        pthread_cond_signal(&_cond);
    }
    void allthreadsleep(const ThreadData &data)
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", data._name.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }
    void pthread_Run(ThreadData &data)
    {
        while (true)
        {
            T t;
            {
                LockGuard ld(&_mutex);
                if (_taskq.empty())
                {
                    allthreadsleep(data);
                }
                t = _taskq.front();

                _taskq.pop();
            }

            t();
            {
                LockGuard ld(&_mutex);
                lg.LogMessage(Info, "Thread name:%s is handling: %s \n", data._name.c_str(), t.PrintTask().c_str());
                lg.LogMessage(Info, "Thread name:%s get result: %s \n", data._name.c_str(), t.PrintResult().c_str());
            }
        }
    }

    void Start()
    {
        for (auto &th : _ptdv)
        {
            th.Start();
            lg.LogMessage(Info, "%s is running ...\n", th.Threadname().c_str());
        }
    }
    void Push(T &task)
    {

        {
            LockGuard ld(&_mutex);

            _taskq.push(task);

            // 插入任务后唤醒进程
            allthreadwakeup();
        }
    }

    // Just for debug success!
    void Wait()
    {
        for (auto &th : _ptdv)
        {
            th.Join();
        }
    }
    ~pthread_pool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

private:
    queue<T> _taskq;
    vector<Thread<ThreadData>> _ptdv;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    int _thread_num;
    static pthread_pool *instance;
    static pthread_mutex_t _sig_ins;
};
template <class T>
pthread_pool<T> *pthread_pool<T>::instance = nullptr;
template <class T>
pthread_mutex_t pthread_pool<T>::_sig_ins = PTHREAD_MUTEX_INITIALIZER;

线程池单利化问题

cpp 复制代码
  static pthread_pool<T> *Getinstance()
    {
        if (instance == nullptr)
        {
            pthread_mutex_lock(&_sig_ins);
            if (instance == nullptr)
            {
                instance = new pthread_pool<T>(defaultthreadnum);
                lg.LogMessage(Info, "instance is create succeess...\n");
                return instance;
            }
            
        }
        
    }

在获取单例的函数中,我们是需要加锁的,防止多个线程同时进入创建出多个单利。

相关推荐
懒大王爱吃狼43 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷2 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
阿伟*rui2 小时前
配置管理,雪崩问题分析,sentinel的使用
java·spring boot·sentinel
待磨的钝刨2 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj4 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck4 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei4 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师5 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉5 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer5 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法