首页 > 编程语言 >c++ 程序通用多线程单例设计 c++ web 框架设计经验谈

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

时间:2023-02-15 13:33:24浏览次数:38  
标签:std obj temp 经验谈 cache iter c++ 多线程 exptime

设计 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

标签:std,obj,temp,经验谈,cache,iter,c++,多线程,exptime
From: https://www.cnblogs.com/paozhu/p/17122489.html

相关文章

  • C++构造函数的两种实现方式
    C++构造函数的两种实现方式下面两种方式等价structListNode{intval;ListNode*next;ListNode(val){intval=val;next=nullptr......
  • C++ 计时
    ctimeclock()是一个无参函数,返回值是一个以毫秒为单位的整形#include<ctime>#include<iostream>longt1=clock();****Doingsomething......
  • C++特殊成员
    参考书籍:C++PrimerEssentialC++编译器:gcc/g++C++特殊成员const成员const修饰的数据成员初始化必须采用初始化参数列表不能被修改构造函数必须要初始化常数据成员cons......
  • C++基础入门(超详细)
    话不多说,序言搞起来:自从开始学老师布置的任务后,目前还是OpenCV,哈~哈。我就莫名问老师:“以后编程是用C++还是python?”,果然还是太年轻,老师说:“两们都要精通”。唉!于是乎为期......
  • c++函数指针
    函数的地址是存储其机器语言代码的内存的开始地址。通常,这些地址对用户而言,既不重要,也没有什么用处,但对程序而言,却很有用。例如,可以编写将另一个函数的地址作为参数的函数。......
  • 解决在Windows上Android Studio写C/C++代码无法补全,没有代码提示的问题
    之前一直在Linux上开发应用,最近因为工作需要,系统切回了Windows,因为之前在Linux上的AndroidStudio中写C/C++代码很正常,该有的代码提示功能都有。但是在迁移到Windows上后......
  • C++ uppper_bound 使用
     map的key,默认按照从小到达排序;upper_bound(4),  #include<iostream>#include<vector>#include<map>#include<algorithm>usingnamespacestd;intmai......
  • 实现C++和C的混合编程
    实现C++和C的混合编程在C++出现之前,很多实用的功能都是用C语言开发的,很多底层的库也是用C语言编写的。这意味着,如果能在C++代码中兼容C语言代码,无疑能极大地提......
  • C/C++程序设计课程设计[2023-02-15]
    C/C++程序设计课程设计[2023-02-15]程序设计课程设计要求1、课程设计分组合作完成,每个小组最多3人。2、每组成员(不得超过3人)分工合作完成一个课程设计题目,每个人的任......
  • C++类的组合
    title:C++类的组合案例date:2022-05-1819:07:35tags:C++category:cpp参考书籍:C++PrimerEssentialC++编译器:gcc/g++C++类的组合什么是类的组合类的组合就是以......