设计 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. 😀 Java并发 - (并发基础)

    Java并发 - (并发基础) 1.什么是共享资源 堆是被所有线程共享的一块内存区域.在虚拟机启动时创建.此内存区域的唯一目的就是存放对象实例 Java中几乎所有的对象实例都在这里分配内存.方法区与堆 ...

  2. 在 Solidity 中 ++i 为什么比 i++ 更省 Gas?

    前言 作为一个初学者,"在 Solidity 中 ++i 为什么比 i++ 更省 Gas?" 这个问题始终在每个寂静的深夜困扰着我.也曾在网上搜索过相关问题,但没有得到根本性的解答 ...

  3. 第一章:seaborn图形美学

    一.seaborn模板 1 import numpy as np 2 import matplotlib.pyplot as plt 3 4 def sinplot(flip=1): 5 x = np ...

  4. 【Shell案例】【for循环、seq生成】3、输出7的倍数

    描述写一个 bash脚本以输出数字 0 到 500 中 7 的倍数(0 7 14 21...)的命令 方法1:in方式循环 [if的括号是中括号,中间的条件要有空格] [循环体用do和done配对] ...

  5. 【基于OpenAI的ChatGPT】搭建属于自己的微信聊天机器人(附带注册英国手机号码方式)

    前言:这几天 OpenAI的聊天机器人很火,前两天也爆发了很多关于ChatGPT接入微信的文章.我就顺便[借用别人已有的项目],来部署一个属于自己的微信聊天机器人.项目地址见下文. 1.首先需要有一个 ...

  6. vue-cli3打包时vue-cli-service build怎么分不同环境(npm run build:stage和npm run build:prod)

  7. vue 单独封装分页组件

    一.在components文件夹下新建 pagination.vue <template> <div class="page-wrap"> <ul&g ...

  8. Vuex从入门到精通

    一.vuex介绍 目标 什么是Vuex 为什么学习Vuex 通信方案 组件关系 数据通信 父子关系 父传子:props : 子传父:$emit 非父子关系 vuex (一种组件通信方案) Vuex是什 ...

  9. 含辞未吐,声若幽兰,史上最强免费人工智能AI语音合成TTS服务微软Azure(Python3.10接入)

    所谓文无第一,武无第二,云原生人工智能技术目前呈现三足鼎立的态势,微软,谷歌以及亚马逊三大巨头各擅胜场,不分伯仲,但目前微软Azure平台不仅仅只是一个PaaS平台,相比AWS,以及GAE,它应该是目 ...

  10. 三台服务器使用docker搭建redis一主二从三哨兵,概念-搭建-整合springboot

    一.前言 redis在我们企业级开发中是很常见的,但是单个redis不能保证我们的稳定使用,所以我们要建立一个集群. redis有两种高可用的方案: High availability with Re ...