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; ...
随机推荐
- 区分mbr与gpt分区
查看分区类型 [root@localhost ~]# parted -l|egrep 'dev/|Part' Warning: Unable to open /dev/sr0 read-write ( ...
- Spring Security(1)
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 虽然说互联网是一个非常开发.几乎没有边界的信息大海,但说起来有点奇怪的是,每个稍微有点规模的互联网应用都有自己的权限系统,而权限的本质却是是封闭 ...
- input、print、字符串格式化输出
1.使用input(), print()进行用户交互 """ 以前银行取钱只能拿着存折去柜台跟小姐姐交流才可以 你想干嘛 我想取钱 请输入密码 滴滴滴密码 想取多少钱 我 ...
- 解读JVM级别本地缓存Caffeine青出于蓝的要诀2 —— 弄清楚Caffeine的同步、异步回源方式
大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 上一篇文章中,我们继Guava Cac ...
- 搭建漏洞环境及实战——搭建DVWA漏洞环境
DVWA是一款开源的渗透测试漏洞练习平台,其中内涵XSS.SQL注入.文件上传.文件包含.CSRF和暴力破解等各个难度的测试环境. 1.在安装时需要在数据库里创建一个数据库名,进入MySQL管理中的p ...
- Django之ORM表高级操作、增删改查、外键字段连表查、单表查、跨表查、F/Q查询
目录 一.如何开启自己的测试脚本? 二.对表数据的添加.更新.删除 1.create() 变态操作之批量插入数据 2.update() 3.delete() 4.如何查看QuerySet对象执行的sq ...
- 第七节 VOR/DME进近程序保护区的绘制
飞行程序设计软件实践 通过前面六节的练习,2023社区版插件的主要功能都已经使用到了.今天通过VOR/DME非精密进近程序,再将这些功能串起来使用一下.今天的软件,我们使用浩辰CAD2023版(过期后 ...
- [编程基础] Python格式化字符串常量f-string总结
Python格式化字符串常量f-string总结 本文主要总结在Python中如何使用格式化字符串常量f-string(Formatted string literals).在 Python 程序中, ...
- C++ 之 cout 格式化输出
写代码时每次用到格式化输出就各种搜来搜去,今天好好整理一下,方便以后查阅和使用. 参考链接: C++ 之 cout 使用攻略 C++ 格式化输出 首先,加上头文件 #include <ioman ...
- 从Babel开始认识AST抽象语法树
前言 AST抽象语法树想必大家都有听过这个概念,但是不是只停留在听过这个层面呢.其实它对于编程来讲是一个非常重要的概念,当然也包括前端,在很多地方都能看见AST抽象语法树的影子,其中不乏有vue.re ...