经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
c++ 程序通用多线程单例设计 c++ web 框架设计经验谈
来源:cnblogs  作者:游水小鸡  时间:2023/2/17 10:03:56  对本文有异议

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

 

auto [_, success] = obj.insert({hashid, temp});

这个map insert 方法如果存在会插入失败,于是我用API指定是更新过期时间或删除重新添加,这一步巧妙利用了map这个特性,需要c++17以上。

 

然后使用方式就是很简单了

 

  1. pzcache<std::string> &temp_cache = pzcache<std::string>::conn();

 

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

  1.        pzcache<std::string> &temp_cache = pzcache<std::string>::conn();
           std::string namestring = "testname";
  2. std::size_t cache_hashid = std::hash<std::string>{}(namestring);
  3.  
  4. if (temp_cache.check(cache_hashid) > -1)
  5. {
  6. client << " 已经存在,不需要再存 ";
  7. }
  8. else
  9. {
  10. std::string cache_data = "This cache content!";
  11. temp_cache.save(cache_hashid, cache_data, 30);
  12.  
  13. client << "缓存新的内容";
  14. }

 

然后我们在其它线程使用

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

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

 

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

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

https://github.com/hggq/paozhu

原文链接:https://www.cnblogs.com/paozhu/p/17122489.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号