设计 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 框架设计经验谈的更多相关文章

  1. golang web框架设计7:整合框架

    把前面写好的路由器,控制器,日志,都整合在一起 全局变量和初始化 定义一些框架的全局变量 var ( BeeApp *App AppName string AppPath string StaticD ...

  2. golang web框架设计6:上下文设计

    context,翻译为上下文,为什么要设计这个结构?就是把http的请求和响应,以及参数结合在一起,便于集中处理信息,以后框架的扩展等.好多框架比如gin,都是有这个上下文结构. context结构为 ...

  3. golang web框架设计5:配置设计

    配置信息的解析,实现的是一个key=value,键值对的一个配置文件,类似于ini的配置格式,然后解析这个文件,把解析的数据保存到map中,最后调用的时候通过几个string,int之类的函数返回相应 ...

  4. golang web框架设计4:日志设计

    beego的日志设计思路来自于seelog,根据不同的level来记录日志,beego设计的日志是一个轻量级的,采用系统log.Logger接口,默认输出到os.Stdout,用户可以实现这个接口然后 ...

  5. golang web框架设计3:controller设计

    继续学习golang web框架设计 controller作用 MVC设计模式里面的这个C,控制器. Model是后台返回的数据: View是渲染页面,通常是HTML的模板页面: Controller ...

  6. golang web框架设计2:自定义路由

    继续学习谢大的Go web框架设计 HTTP路由 http路由负责将一个http的请求交到对应的函数处理(或者一个struct的方法),路由在框架中相当于一个事件处理器,而这个时间包括 用户请求的路径 ...

  7. golang web框架设计1:框架规划

    GO WEB 编程13节,如何设计一个web框架 学习谢大的web框架设计 总体介绍 实现一个简易的web框架,我们采用mvc模式来进行开发. model:模型,代表数据结构.通常来说,模型类时包含查 ...

  8. 设计模式——通用泛型单例(普通型和继承自MonoBehaviour)

    单例模式是设计模式中最为常见的,不多解释了.但应该尽量避免使用,一般全局管理类才使用单例. 普通泛型单例: public abstract class Singleton<T> where ...

  9. javase基础笔记4——异常/单例和类集框架

    继承 extends final关键 多态 是在继承的基础上 接口 interface 异常 exception 包的访问可控制权限 private default protect public 异常 ...

  10. Qt实现通用模板单例

    #include <QAtomicPointer> #include <QMutex> #include <memory> using namespace std; ...

随机推荐

  1. 删除redis对应key的缓存

    [root@zhyly-pre-002 ~]# /usr/local/redis/bin/redis-cli -p 6379 #登录redis 127.0.0.1:6379> auth 'Red ...

  2. i春秋Fuzz

    点开只有三个单词plz fuzz parameter 大概意思就是让我们疯狂尝试参数... 我们通过url尝试传入参数 ?user=123 ?name=123 ?username=123 ?id=12 ...

  3. ES系列二之常见问题解决

    上篇ES系列一之java端API操作结束后本以为就相安无事了,但生产的问题是层出不穷的:下面我就再记录下近几周遇到的问题以及解决方案: 一 更新ES信息报错 报错信息如下: Use Elasticse ...

  4. Task01:Matplotlib初相识

    一.明晰绘制一张图的组成条件 Figure:最基本的一级 Axes:在Figure上创建子图的容器(如果Figure中仅含一子图,则该容器可省略) Axis:用于处理子图上和坐标轴和网格相关的元素 T ...

  5. FP6397S5 高效、高频同步DC-DC降压变频器IC

    FP6397是一种高效.高频同步DC-DC降压变频器.100%占空比功能提供了低退出操作,延长了便携式系统的电池寿命. 内部同步开关提高了效率,并消除了对外部肖特基二极管的需要.在停机模式下,输入电源 ...

  6. python3中的常见知识点1

    python3中的常见知识点1 简记一些python小知识 字符串输出 docstring(文档字符串) Lambda 函数(匿名函数) python函数之参数调用 参考链接 字符串输出 1.r'原始 ...

  7. L1-064 估值一亿的AI核心代码 (20分)

    L1-064 估值一亿的AI核心代码 (20分) 以上图片来自新浪微博. 本题要求你实现一个稍微更值钱一点的 AI 英文问答程序,规则是: 无论用户说什么,首先把对方说的话在一行中原样打印出来: 消除 ...

  8. RocketMQ 在网易云音乐的实践

    本文作者:蒋星韬,网易云音乐服务端开发工程师. 云音乐线上场景众多,比如直播.评论.广告,各个业务线都会有消息场景比如发奖券,也会有延迟消息和事务消息场景,以及大数据做埋点数据.数据清洗.离线处理等. ...

  9. JS传值与应用

    问题提出:在进行页面书写的时候,有时候需要进行动态页面拼接,在动态拼接的时候,涉及到函数的调用,函数的传值可能是HTML标签,或者含有json的标签,这样在传值时就有可能出现问题,由于"&q ...

  10. 如何配置 SLO

    前言 无论是对外提供 IaaS PaaS SaaS 的云公司,还是提供信息技术服务的乙方公司,亦或是金融 制造等各行各业的数据中心.运维部门,我们的一个非常重要的合同承诺或考核评估指标就是:SLA(即 ...