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


    设计 c++ web 框架时候,想要一个框架缓存类,很多通用缓存类是用字符保存,作为框架内置就不要序列和反序列了,因为框架内部使用。

    想给自己的paozhu c++ web 框架添加缓存类,参考了springboot 于是确定用单例设计模式缓存类模板。

    c++11后静态变量已经统一为线程安全了,网络各种茴香豆几种吃法现在变成一种安全吃法。

    因为框架时候了多线程,也要求最低c++20,所以直接使用新标准单例模式。

    因为需要保存多种类型,于是设计为模版接口,这样一个通用设计 缓存模型想好了,然后就是设计类库API,需要兼容数组和单一对象。

    也要有超时,于是我们确定了基础结构

    1
    2
    3
    4
    5
    struct data_cache_t
    {
        std::vector data;
        unsigned int exptime = 0;
    };

     

    因为我想以后还要动态库也能使用,于是用了一个静态函数做单例

    1
    2
    3
    4
    5
    6
    template <typename BASETYPE_T>
    std::mapsize_t, BASETYPE_T> &get_pz_cache()
    {
        static std::mapsize_t, BASETYPE_T> instance;
        return instance;
    }

     

    模版类需要兼顾数组和单个对象于是统一保存为vector数组,然后套入map对象,因为我们要用size_t做hash键值,这样方便统一长度。

    然后根据不同api返回不同类型。

    先看详细代码,后面讲一个map插入失败情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    template <typename BASE_TYPE>
       class pzcache
       {
       private:
           pzcache(){};
           ~pzcache(){};
           pzcache(const pzcache &);
           pzcache &operator=(const pzcache &);
     
       public:
           struct data_cache_t
           {
               std::vector data;
               unsigned int exptime = 0;
           };
     
       public:
           void save(std::size_t hashid, BASE_TYPE &data_list, int expnum = 0, bool cover_data = false)
           {
               std::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &obj = get_pz_cache();
               std::unique_lock lock(editlock);
               obj.clear();
           }
           int check(std::size_t hashid)
           {
               std::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &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::mapsize_t, data_cache_t> &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 &temp_cache = pzcache::conn();

     

    我们缓存一个string 对象,首先取得单例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    pzcache &temp_cache = pzcache::conn();
           std::string namestring =
    "testname";
        std::size_t cache_hashid = std::hash{}(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 << "缓存新的内容";
        }

     

    然后我们在其它线程使用

    1
    2
    3
    4
    5
    6
    pzcache &temp_cache = pzcache::conn();
     
    std::string namestring = "testname";
    std::size_t cache_hashid = std::hash{}(namestring);
     
    std::string cache_data = temp_cache.get(cache_hashid);

     是不是很简单,c++ 强大的模板能力,一个通用类库设计好了,而且简单好用

     

    欢迎使用 国产 C++ web 框架 paozhu 1.2.0 发布

    源代码里面更多的设计模式可以参考,框架LICENSE反正为MIT模式,大家商用也没有问题。

    https://github.com/hggq/paozhu

  • 相关阅读:
    OpenCV 图像的几何变换
    结构体字节对齐
    浅学Python入门
    React 全栈体系(六)
    你真的知道什么是正弦和余弦吗?使用 Python 和 Turtle 可视化数学
    KILM: Knowledge Injection into Encoder-Decoder Language Models
    TensorFlow学习:使用官方模型和自己的训练数据进行图片分类
    STM32实战总结:HAL之SDIO
    裸辞半年,靠着这套Java面试宝典,拿下了腾讯T3
    单点故障解决方案之Smart Link与Monitor Link
  • 原文地址:https://www.cnblogs.com/paozhu/p/17122489.html