数据人与超自然意识 发表于 2023-2-15 12:40:05

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   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 &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 = obj.insert({hashid, temp});            if (!success)            {                if (cover_data)                {                  obj = temp;                }                else                {                  obj.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 = obj.insert({hashid, temp});            if (!success)            {                if (cover_data)                {                  obj = temp;                }                else                {                  obj.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;                  }                }                if (iter->second.exptime >= nowtime)                {                  if (iter->second.data.size() > 0)                  {                        return iter->second.data;                  }                }                else                {                  obj.erase(iter++);                }            }            lock.unlock();            BASE_TYPE temp;            return temp;      }      static pzcache &conn()      {            static pzcache instance;            return instance;      }    public:      std::mutex editlock;    }; 
auto = 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{}(namestring);            if (temp_cache.check(cache_hashid) > -1)            {                  client
页: [1]
查看完整版本: c++ 程序通用多线程单例设计 c++ web 框架设计经验谈