已解决
【Linux】系统编程线程池单例模式(C++)
来自网友在路上 151851提问 提问时间:2023-09-25 08:40:06阅读次数: 51
最佳答案 问答题库518位专家为你答疑解惑
目录
【1】什么是单例模式
【2】什么是设计模式
【3】单例模式的特点
【4】饿汉实现方式和懒汉实现方式
【5】饿汉方式实现单例模式
【6】懒汉方式实现单例模式
【7】将线程池改为单例模式
【1】什么是单例模式
单例模式是一种 "经典的, 常用的, 常考的" 设计模式。
【2】什么是设计模式
IT行业这么火, 涌入的人很多. 俗话说林子大了啥鸟都有. 大佬和菜鸡们两极分化的越来越严重. 为了让菜鸡们不太拖大佬的后腿, 于是大佬们针对一些经典的常见的场景, 给定了一些对应的解决方案, 这个就是 设计模式。
【3】单例模式的特点
某些类, 只应该具有一个对象(实例), 就称之为单例,例如一个男人只能有一个媳妇。
在很多服务器开发场景中, 经常需要让服务器加载很多的数据 (上百G) 到内存中. 此时往往要用一个单例的类来管理这些数据。
【4】饿汉实现方式和懒汉实现方式
【洗完的例子】
-
吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭。
-
吃完饭, 先把碗放下, 然后下一顿饭用到这个碗了再洗碗, 就是懒汉方式。
懒汉方式最核心的思想是 "延时加载". 从而能够优化服务器的启动速度。
【5】饿汉方式实现单例模式
template <typename T>
class Singleton {static T data;
public:static T* GetInstance() {return &data;}
};
【6】懒汉方式实现单例模式
template <typename T>
class Singleton {static T* inst;
public:static T* GetInstance() {if (inst == NULL) {inst = new T();} return inst;}
};
【7】将线程池改为单例模式
【Makefile文件】
# 创建变量关联关系
cc=c++
standard=-std=c++11
linkLib=-l pthread
# 创建编译文件依赖关系
myThreadPool:ThreadPool.cc$(cc) -o $@ $^ $(standard) $(linkLib)
# 创建删除命令
.PHONY:clean
clean:rm -f myThreadPool
【LockGuard.hpp文件】
#pragma once
#include <pthread.h>
/* 锁控制类 */
class Mutex {
public:/* 构造函数 */Mutex(pthread_mutex_t* lock = nullptr) : _tdLock(lock){}
/* 析构函数 */~Mutex(){};
/* 加锁函数 */void Lock() {if(_tdLock != nullptr) { pthread_mutex_lock(_tdLock); }}
/* 解锁函数 */void unLock() {if(_tdLock != nullptr) { pthread_mutex_unlock(_tdLock);}}
private:pthread_mutex_t* _tdLock;
};
/* 锁操作类 */
class LockGuard {
public:/* 构造函数 */LockGuard(pthread_mutex_t* mutex) : _mutex(mutex){_mutex.Lock();}
/* 析构函数 */~LockGuard() {_mutex.unLock();}
private:Mutex _mutex;
};
【Thread.hpp文件】
#pragma once
#include <iostream>
#include <functional>
#include <cstdio>
#include <cassert>
namespace ThreadNs
{/* 线程连接上下文 */class Thread;class ConnectText{public:/* 构造函数 */ConnectText() : _this(nullptr), _args(nullptr) {}/* 析构函数 */~ConnectText() {}
public:Thread *_this;void *_args;};
/* 线程类封装 */class Thread{public:using func_t = std::function<void *(void *)>; // // 从定义类似函数指针类型:返回值是:void* 参数是:void*
public:/* 构造函数 */Thread(const int number = 0){// 创建线程的名称char buffer[64];snprintf(buffer, sizeof(buffer), "Thread-%d", number);_tName = buffer;}
/* 析构函数 */~Thread() {}public:/* 线程启动 */void Start(const func_t& func, void *args = nullptr){// 建立关系_func = func;_args = args;
// 创建线程后,启动ConnectText *cnt = new ConnectText();cnt->_this = this;cnt->_args = _args;
int n = pthread_create(&_tid, nullptr, StartRoutine, (void *)cnt);assert(n == 0); (void)n; // 编译debug的方式时assert是存在的,release方式assert是不存在的,到时n就是定义了,但是没有被使用的变量。// 在有的编译器下会有warning。}
/* 线程等待 */void Join(){int n = pthread_join(_tid, nullptr);assert(n == 0);(void)n;}
public:/* 获取线程名字 */std::string GetThreadName(){return _tName;}
private:/* 线程函数 */static void *StartRoutine(void *args){ // 在类内创建线程,想让线程执行对应的方法,需要将方法设置称为staticConnectText *cnt = static_cast<ConnectText *>(args);void *exRet = cnt->_this->RoutineRun(cnt->_args);delete cnt;return exRet;}
void *RoutineRun(void *args){return _func(args);}
private:pthread_t _tid; // 线程idstd::string _tName; // 线程名称func_t _func; // 线程函数void *_args; // 线程参数};
}
【Task.hpp文件】
#pragma once
#include <iostream>
#include <string>
#include <functional>
/* 计算任务 */
class CalTask
{
public:using func_t = std::function<int(int, int, char)>;
public:/* 构造函数 */CalTask() {}
/* 构造函数 */CalTask(int x, int y, char op, func_t func): _x(x), _y(y), _op(op), _callBalk(func){}
public:/* 仿函数 */std::string operator()(){int result = _callBalk(_x, _y, _op);
char buffer[64];snprintf(buffer, sizeof(buffer), "%d %c %d = %d", _x, _op, _y, result);return buffer;}
public:/* 返回打印公式 */std::string ToTaskString(){char buffer[64];snprintf(buffer, sizeof(buffer), "%d %c %d = ?", _x, _op, _y);return buffer;}
private:int _x;int _y;char _op;func_t _callBalk;
};
/* 执行计算的方法 */
int MyCalculate(int x, int y, char op)
{int result = 0;switch (op){case '+':result = x + y;break;
case '-':result = x - y;break;
case '*':result = x * y;break;
case '/':{if (y == 0){std::cerr << "div zero error!" << std::endl;result = -1;}else{result = x / y;}break;}
case '%':{if (y == 0){std::cerr << "mod zero error!" << std::endl;result = -1;}else{result = x % y;}break;}
default:break;}
return result;
}
/* 保存任务 */
class SaveTask
{
public:using func_t = std::function<void(const std::string &)>;
public:/* 构造函数 */SaveTask() {}/* 构造函数 */SaveTask(const std::string &message, func_t func): _message(message), _callBalk(func){}
public:/* 仿函数 */void operator()(){_callBalk(_message);}
private:std::string _message;func_t _callBalk;
};
/* 保存方法 */
void Save(const std::string& massage){std::string target = "./log.txt";FILE *fp = fopen(target.c_str(), "a+");if(fp == NULL){std::cerr << "fopen fail!" << std::endl;return;}
fputs(massage.c_str(), fp);fputs("\n", fp);fclose(fp);
}
【ThreadPool.hpp文件】
#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <mutex>
#include <pthread.h>
#include "Thread.hpp"
#include "LockGuard.hpp"
/* 引用命名空间 */
using namespace ThreadNs;
/* 线程上下文数据 */
template <class T>
class ThreadPool;
template <class T>
class ThreadData
{
public:ThreadData(ThreadPool<T> *tp, const std::string &n): _threadPool(tp), _name(n){}
public:ThreadPool<T> *_threadPool;std::string _name;
};
/* 线程池封装 */
const int g_num = 5; // 设置线程数
template <class T>
class ThreadPool
{
public:/* (单例模式获取对象方法) */static ThreadPool<T> *GetInstance(){if(nullptr == tp){_singlock.lock();if(nullptr == tp){tp = new ThreadPool<T>();}_singlock.unlock();return tp;}}
/* 析构函数 */~ThreadPool(){// 释放线程锁pthread_mutex_destroy(&_mutex);// 释放线程条件变量pthread_cond_destroy(&_cond);
// 遍历释放for (auto &t : _threads){delete t;}}
public:/* 开启线程池 */void Run(){// 启动线程for (const auto &t : _threads){ThreadData<T> *td = new ThreadData<T>(this, t->GetThreadName());t->Start(HandlerTask, td);std::cout << t->GetThreadName() << ": Start..." << std::endl;}
// // 阻塞式等待回收线程// for (const auto &t : _threads)// {// t->Join();// std::cout << t->GetThreadName() << ": Recycle..." << std::endl;// }}
public:/* 获取锁 */pthread_mutex_t *Mutex() { return &_mutex; }/* 线程加锁 */void Lock() { pthread_mutex_lock(&_mutex); }/* 线程解锁 */void UnLock() { pthread_mutex_unlock(&_mutex); }/* 线程等待 */void ThreadWait() { pthread_cond_wait(&_cond, &_mutex); }/* 判断是否有任务 */bool IsEmpty() { return _taskQueue.empty(); }
/* 新增任务 */void Push(const T &in){// 加锁->自动解锁LockGuard LockGuard(&_mutex);// 新增任务_taskQueue.push(in);// 环形线程执行pthread_cond_signal(&_cond);}
/* 执行任务 */T Pop(){// 创建T对象T t;// 获取栈顶任务t = _taskQueue.front();_taskQueue.pop();// 返回任务return t;}
private:/* 构造函数(改写为单例模式) */ThreadPool(const int &num = g_num): _threadNum(num){// 初始化线程锁pthread_mutex_init(&_mutex, nullptr);// 初始化线程条件变量pthread_cond_init(&_cond, nullptr);
// 将每个线程地址Push到线程地址容器中for (int i = 0; i < _threadNum; i++){_threads.push_back(new Thread(i + 1));}}
/* 拷贝构造禁用 */ThreadPool(const ThreadPool&) = delete;/* 赋值拷贝禁用 */void operator=(const ThreadPool&) = delete;
/* 线程池共享线程 */static void *HandlerTask(void* args){ThreadData<T> *td = static_cast<ThreadData<T> *>(args);
while (true){// 创建任务对象T t;
{// 加锁->自动解锁LockGuard LockGuard(td->_threadPool->Mutex());// 如果没有任务,等待任务if (td->_threadPool->IsEmpty()){td->_threadPool->ThreadWait();}t = td->_threadPool->Pop();// 解锁td->_threadPool->UnLock();}
// 打印信息std::cout << td->_name << ":承接一个任务[" << t.ToTaskString() << "],任务的执行结果是[" << t() << "]" << std::endl;}return nullptr;}
private:int _threadNum; // 线程数量std::vector<Thread *> _threads; // 存放线程地址的容器std::queue<T> _taskQueue; // 存放线程任务的队列pthread_mutex_t _mutex; // 线程锁pthread_cond_t _cond; // 线程条件变量
static ThreadPool<T> *tp;static std::mutex _singlock;
};
template<class T>
ThreadPool<T> * ThreadPool<T>::tp = nullptr;
template<class T>
std::mutex ThreadPool<T>::_singlock;
【ThreadPool.cc文件】
#include <iostream>
#include <memory>
#include <unistd.h>
#include "Task.hpp"
#include "ThreadPool.hpp"
using namespace std;
int main()
{// 智能指针管理// unique_ptr<ThreadPool<CalTask>> tP(new ThreadPool<CalTask>());ThreadPool<CalTask>::GetInstance()->Run();// 启动线程池// tP->Run();
// 手动派发任务int x;int y;char op;while (1){std::cout << "请输入数据1# ";std::cin >> x;std::cout << "请输入数据2# ";std::cin >> y;std::cout << "请输入要进行的运算# ";std::cin >> op;CalTask t(x, y, op, MyCalculate);ThreadPool<CalTask>::GetInstance()->Push(t);sleep(1);}return 0;
}
查看全文
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"【Linux】系统编程线程池单例模式(C++)":http://eshow365.cn/6-13354-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!
- 上一篇: WebGL 用鼠标控制物体旋转
- 下一篇: 华为NFC设置教程(门禁卡/公交卡/校园卡等)