c++ 程序通用多线程单例设计 c++ web 框架设计经验谈

打印 上一主题 下一主题

主题 907|帖子 907|积分 2721

设计 c++ web 框架时候,想要一个框架缓存类,很多通用缓存类是用字符保存,作为框架内置就不要序列和反序列了,因为框架内部使用。
想给自己的paozhu c++ web 框架添加缓存类,参考了springboot 于是确定用单例设计模式缓存类模板。
c++11后静态变量已经统一为线程安全了,网络各种茴香豆几种吃法现在变成一种安全吃法。
因为框架时候了多线程,也要求最低c++20,所以直接使用新标准单例模式。
因为需要保存多种类型,于是设计为模版接口,这样一个通用设计 缓存模型想好了,然后就是设计类库API,需要兼容数组和单一对象。
也要有超时,于是我们确定了基础结构
  1.         struct data_cache_t
  2.         {
  3.             std::vector<BASE_TYPE> data;
  4.             unsigned int exptime = 0;
  5.         };
复制代码
 
因为我想以后还要动态库也能使用,于是用了一个静态函数做单例
  1.     template <typename BASETYPE_T>
  2.     std::map<std::size_t, BASETYPE_T> &get_pz_cache()
  3.     {
  4.         static std::map<std::size_t, BASETYPE_T> instance;
  5.         return instance;
  6.     }
复制代码
 
模版类需要兼顾数组和单个对象于是统一保存为vector数组,然后套入map对象,因为我们要用size_t做hash键值,这样方便统一长度。
然后根据不同api返回不同类型。
先看详细代码,后面讲一个map插入失败情况
  1. template     class pzcache    {    private:        pzcache(){};        ~pzcache(){};        pzcache(const pzcache &);        pzcache &operator=(const pzcache &);    public:        struct data_cache_t
  2.         {
  3.             std::vector<BASE_TYPE> data;
  4.             unsigned int exptime = 0;
  5.         };    public:        void save(std::size_t hashid, BASE_TYPE &data_list, int expnum = 0, bool cover_data = false)        {            std::map &obj = get_pz_cache();            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 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 &data_list, int expnum = 0, bool cover_data = false)        {            std::map &obj = get_pz_cache();            struct data_cache_t temp;            temp.data = data_list;            if (expnum != 0)            {                temp.exptime = http::timeid() + expnum;            }            else            {                temp.exptime = 0;            }            std::unique_lock 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 &obj = get_pz_cache();            std::unique_lock lock(editlock);            auto iter = obj.find(hashid);            if (iter != obj.end())            {                obj.erase(iter++);                return true;            }            return false;        }        void remove_exptime()        {            std::map &obj = get_pz_cache();            unsigned int nowtime = http::timeid();            std::unique_lock 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 &obj = get_pz_cache();            std::unique_lock lock(editlock);            obj.clear();        }        int check(std::size_t hashid)        {            std::map &obj = get_pz_cache();            unsigned int nowtime = http::timeid();            std::unique_lock 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 &obj = get_pz_cache();            unsigned int nowtime = http::timeid() + exptime;            if (exptime == 0)            {                nowtime = 0;            }            std::unique_lock 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 get_array(std::size_t hashid)        {            std::map &obj = get_pz_cache();            unsigned int nowtime = http::timeid();            std::unique_lock 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 temp;            return temp;        }        BASE_TYPE get(std::size_t hashid)        {            std::map &obj = get_pz_cache();            unsigned int nowtime = http::timeid();            std::unique_lock 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以上。
 
然后使用方式就是很简单了
 
  1. pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
复制代码
 
我们缓存一个string 对象,首先取得单例。
[code]        pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
       std::string namestring = "testname";            std::size_t cache_hashid = std::hash{}(namestring);            if (temp_cache.check(cache_hashid) > -1)            {                  client
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

数据人与超自然意识

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表