c++ 程序通用多线程单例设计 c++ web 框架设计经验谈
设计 c++ web 框架时候,想要一个框架缓存类,很多通用缓存类是用字符保存,作为框架内置就不要序列和反序列了,因为框架内部使用。
想给自己的paozhu c++ web 框架添加缓存类,参考了springboot 于是确定用单例设计模式缓存类模板。
c++11后静态变量已经统一为线程安全了,网络各种茴香豆几种吃法现在变成一种安全吃法。
因为框架时候了多线程,也要求最低c++20,所以直接使用新标准单例模式。
因为需要保存多种类型,于是设计为模版接口,这样一个通用设计 缓存模型想好了,然后就是设计类库API,需要兼容数组和单一对象。
也要有超时,于是我们确定了基础结构
struct data_cache_t
{
std::vector<BASE_TYPE> data;
unsigned int exptime = 0;
};
因为我想以后还要动态库也能使用,于是用了一个静态函数做单例
template <typename BASETYPE_T>
std::map<std::size_t, BASETYPE_T> &get_pz_cache()
{
static std::map<std::size_t, BASETYPE_T> instance;
return instance;
}
模版类需要兼顾数组和单个对象于是统一保存为vector数组,然后套入map对象,因为我们要用size_t做hash键值,这样方便统一长度。
然后根据不同api返回不同类型。
先看详细代码,后面讲一个map插入失败情况
template <typename BASE_TYPE>
class pzcache
{
private:
pzcache(){};
~pzcache(){};
pzcache(const pzcache &);
pzcache &operator=(const pzcache &); public:
struct data_cache_t
{
std::vector<BASE_TYPE> data;
unsigned int exptime = 0;
}; public:
void save(std::size_t hashid, BASE_TYPE &data_list, int expnum = 0, bool cover_data = false)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
struct data_cache_t temp;
temp.data.push_back(data_list);
if (expnum != 0)
{
temp.exptime = http::timeid() + expnum;
}
else
{
temp.exptime = 0;
}
std::unique_lock<std::mutex> lock(editlock);
auto [_, success] = obj.insert({hashid, temp});
if (!success)
{
if (cover_data)
{
obj[hashid] = temp;
}
else
{
obj[hashid].exptime = temp.exptime;
}
}
}
void save(std::size_t hashid, std::vector<BASE_TYPE> &data_list, int expnum = 0, bool cover_data = false)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
struct data_cache_t temp;
temp.data = data_list;
if (expnum != 0)
{
temp.exptime = http::timeid() + expnum;
}
else
{
temp.exptime = 0;
}
std::unique_lock<std::mutex> lock(editlock);
auto [_, success] = obj.insert({hashid, temp});
if (!success)
{
if (cover_data)
{
obj[hashid] = temp;
}
else
{
obj[hashid].exptime = temp.exptime;
}
}
}
bool remove(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
obj.erase(iter++);
return true;
}
return false;
}
void remove_exptime()
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
for (auto iter = obj.begin(); iter != obj.end();)
{
if (iter->second.exptime == 0)
{
continue;
}
if (iter->second.exptime < nowtime)
{
obj.erase(iter++);
}
}
}
void clear()
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
std::unique_lock<std::mutex> lock(editlock);
obj.clear();
}
int check(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
return 0;
}
int temp = (int)(iter->second.exptime - nowtime);
if (temp == -1)
{
return -2;
}
return temp;
}
return -1;
} int update(std::size_t hashid, int exptime = 0)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid() + exptime;
if (exptime == 0)
{
nowtime = 0;
}
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
iter->second.exptime = nowtime;
return 0;
}
iter->second.exptime = nowtime;
return 1;
}
return -1;
}
std::vector<BASE_TYPE> get_array(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
return iter->second.data;
} if (iter->second.exptime >= nowtime)
{
return iter->second.data;
}
else
{
obj.erase(iter++);
}
}
lock.unlock();
std::vector<BASE_TYPE> temp;
return temp;
}
BASE_TYPE get(std::size_t hashid)
{
std::map<std::size_t, data_cache_t> &obj = get_pz_cache<data_cache_t>();
unsigned int nowtime = http::timeid();
std::unique_lock<std::mutex> lock(editlock);
auto iter = obj.find(hashid);
if (iter != obj.end())
{
if (iter->second.exptime == 0)
{
if (iter->second.data.size() > 0)
{
return iter->second.data[0];
}
} if (iter->second.exptime >= nowtime)
{
if (iter->second.data.size() > 0)
{
return iter->second.data[0];
}
}
else
{
obj.erase(iter++);
}
}
lock.unlock();
BASE_TYPE temp;
return temp;
}
static pzcache &conn()
{
static pzcache instance;
return instance;
} public:
std::mutex editlock;
};
auto [_, success] = obj.insert({hashid, temp});
这个map insert 方法如果存在会插入失败,于是我用API指定是更新过期时间或删除重新添加,这一步巧妙利用了map这个特性,需要c++17以上。
然后使用方式就是很简单了
pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
我们缓存一个string 对象,首先取得单例。
pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
std::string namestring = "testname";
std::size_t cache_hashid = std::hash<std::string>{}(namestring); if (temp_cache.check(cache_hashid) > -1)
{
client << " 已经存在,不需要再存 ";
}
else
{
std::string cache_data = "This cache content!";
temp_cache.save(cache_hashid, cache_data, 30); client << "缓存新的内容";
}
然后我们在其它线程使用
pzcache<std::string> &temp_cache = pzcache<std::string>::conn(); std::string namestring = "testname";
std::size_t cache_hashid = std::hash<std::string>{}(namestring); std::string cache_data = temp_cache.get(cache_hashid);
是不是很简单,c++ 强大的模板能力,一个通用类库设计好了,而且简单好用
欢迎使用 国产 C++ web 框架 paozhu 1.2.0 发布
源代码里面更多的设计模式可以参考,框架LICENSE反正为MIT模式,大家商用也没有问题。
https://github.com/hggq/paozhu
c++ 程序通用多线程单例设计 c++ web 框架设计经验谈的更多相关文章
- golang web框架设计7:整合框架
把前面写好的路由器,控制器,日志,都整合在一起 全局变量和初始化 定义一些框架的全局变量 var ( BeeApp *App AppName string AppPath string StaticD ...
- golang web框架设计6:上下文设计
context,翻译为上下文,为什么要设计这个结构?就是把http的请求和响应,以及参数结合在一起,便于集中处理信息,以后框架的扩展等.好多框架比如gin,都是有这个上下文结构. context结构为 ...
- golang web框架设计5:配置设计
配置信息的解析,实现的是一个key=value,键值对的一个配置文件,类似于ini的配置格式,然后解析这个文件,把解析的数据保存到map中,最后调用的时候通过几个string,int之类的函数返回相应 ...
- golang web框架设计4:日志设计
beego的日志设计思路来自于seelog,根据不同的level来记录日志,beego设计的日志是一个轻量级的,采用系统log.Logger接口,默认输出到os.Stdout,用户可以实现这个接口然后 ...
- golang web框架设计3:controller设计
继续学习golang web框架设计 controller作用 MVC设计模式里面的这个C,控制器. Model是后台返回的数据: View是渲染页面,通常是HTML的模板页面: Controller ...
- golang web框架设计2:自定义路由
继续学习谢大的Go web框架设计 HTTP路由 http路由负责将一个http的请求交到对应的函数处理(或者一个struct的方法),路由在框架中相当于一个事件处理器,而这个时间包括 用户请求的路径 ...
- golang web框架设计1:框架规划
GO WEB 编程13节,如何设计一个web框架 学习谢大的web框架设计 总体介绍 实现一个简易的web框架,我们采用mvc模式来进行开发. model:模型,代表数据结构.通常来说,模型类时包含查 ...
- 设计模式——通用泛型单例(普通型和继承自MonoBehaviour)
单例模式是设计模式中最为常见的,不多解释了.但应该尽量避免使用,一般全局管理类才使用单例. 普通泛型单例: public abstract class Singleton<T> where ...
- javase基础笔记4——异常/单例和类集框架
继承 extends final关键 多态 是在继承的基础上 接口 interface 异常 exception 包的访问可控制权限 private default protect public 异常 ...
- Qt实现通用模板单例
#include <QAtomicPointer> #include <QMutex> #include <memory> using namespace std; ...
随机推荐
- 关于Go你不得不知道的小技巧
目录 Go 箴言 Go 之禅 代码 使用 go fmt 格式化 多个 if 语句可以折叠成 switch 用 chan struct{} 来传递信号, chan bool 表达的不够清楚 30 * t ...
- PHY驱动调试之 --- MDIO/MDC接口22号和45号条款(一)
最近在调试一款Phy的驱动,从没有任何头绪到略有了解经历了太多的痛苦,于是决定写这个系列篇记录一下.特别感谢无数优秀的博主无私奉献很多优秀的博文给予了我很大的帮助.在这个系列篇中,我也会转载部分优秀的 ...
- <二>自己实现简单的string
我们结合运算符重载知识实现string 类 在自己实现的String类中可以参考C++中string的方法 例如构造,加法,大小比较,长度,[] 等操作. 当前的MyString 类中,暂时不加入迭代 ...
- 解决python3解压文件名乱码问题(unzip)
看来很多文章,不过我觉得最有效的还是改源码,因为我用的sublime text 3有插件Anaconda可以很方便的跳转到源码文件,你也可以入python3 的安装目录, 搜索 zipfile.py这 ...
- win7修改开机动画
开机动画的修改 首先win7的过场动画是存在于C:\Windows\System32\bootres.dll ,而修改过程动画就需要修改这个dll,我不会改,所以只能用工具美化大师,软媒魔方里面的一个 ...
- 关于sublime text 3写一个插件
前言 我之前一直想写一个记录自己笔记的软件,可以给因为我都记录在桌面的便签上很乱,以至于便签上满满的全是字母,很难看,但是我有不想写图形化界面,所以最终我选择了写一个sublime 插件,功能就是记录 ...
- 【每日一题】【动态规划】2022年1月30日-NC127 最长公共子串
描述 给定两个字符串str1和str2,输出两个字符串的最长公共子串 题目保证str1和str2的最长公共子串存在且唯一. 方法1:dp数组存子串 import java.util.*; public ...
- AcWing1137. 选择最佳线路
题目传送门 题目大意 \(\qquad\)有一张有向图,可以有若干个起点,只有一个终点,求所有起点到终点的最短路中最短的一条,若所有起点都与终点不连通,则输出\(-1\) 解题思路 \(\qquad\ ...
- STL string常用API
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string> using namespace std; ...
- python 集合常用操作
集合的特性 无序.不重复.可迭代 常用api 创建一个集合 需要显式地使用set()方法来声明,如果使用字面量{}来声明解析器会认为这是一个字典. add() 往集合中添加一个元素 demo = se ...