当C++遇到IOS应用开发---LRUCache缓存

2023-11-23 06:48

本文主要是介绍当C++遇到IOS应用开发---LRUCache缓存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/daizhj/article/details/8178807


 本文着重介绍如何在XCODE中,通过C++开发在IOS环境下运行的缓存功能。算法基于LRU(最近最少使用)。有关lru详见:
      http://en.wikipedia.org/wiki/Page_replacement_algorithm#Least_recently_used
      
      之前在网上看到过网友的一个C++实现,感觉不错,所以核心代码就采用了他的设计。相关链接如下:
      http://www.cppblog.com/red22/articles/62499.html

      原作者通过两个MAP对象来记录缓存数据和LRU队列,注意其中的LRU队列并不是按照常用的方式使用LIST链表,而是使用MAP来代替LIST,有关这一点原作者已做了说明。
    
      另外还有人将MRU与LRU组合在一起使用,当然如果清楚了设计原理,那么就很容易理解了,比如这个开源项目:http://code.google.com/p/lru-cache-cpp/

      考虑到缓存实现多数使用单例模式,这里使用C++的模版方式设计了一个Singlton基类,这样以后只要继承该类,子类就会支持单例模式了。其代码如下:
 

[cpp]  view plain copy
  1. //  
  2. //  SingltonT.h  
  3. //  
  4.   
  5. #ifndef SingltonT_h  
  6. #define SingltonT_h  
  7. #include <iostream>  
  8. #include <tr1/memory>  
  9. using namespace std;  
  10. using namespace std::tr1;  
  11. template <typename T>  
  12. class Singlton {  
  13. public:  
  14.       static T* instance();  
  15.       ~Singlton() {  
  16.           cout << "destruct singlton" << endl;  
  17.       }  
  18. protected:  
  19.       Singlton();  
  20. //private:  
  21. protected:  
  22.       static std::tr1::shared_ptr<T> s_instance;  
  23.       //Singlton();  
  24. };  
  25.   
  26. template <typename T>  
  27. std::tr1::shared_ptr<T> Singlton<T>::s_instance;  
  28.    
  29. template <typename T>  
  30. Singlton<T>::Singlton() {  
  31.     cout << "construct singlton" << endl;  
  32. }  
  33.    
  34. template <typename T>  
  35. T* Singlton<T>::instance() {  
  36.     if (!s_instance.get())  
  37.         s_instance.reset(new T);  
  38.     return s_instance.get();  
  39. }  



       另外考虑到在多线程下对static单例对象进行操作,会出现并发访问同步的问题,所以这里使用了读写互斥锁来进行set(设置数据)的同步。如下:
[cpp]  view plain copy
  1. #ifndef _RWLOCK_H_  
  2. #define _RWLOCK_H_  
  3.   
  4. #define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}  
  5. #define UNLOCK(q) __sync_lock_release(&(q)->lock);  
  6.   
  7. struct rwlock {  
  8.     int write;  
  9.     int read;  
  10. };  
  11.   
  12. static inline void  
  13. rwlock_init(struct rwlock *lock) {  
  14.     lock->write = 0;  
  15.     lock->read = 0;  
  16. }  
  17.   
  18. static inline void  
  19. rwlock_rlock(struct rwlock *lock) {  
  20.     for (;;) {//不断循环,直到对读计数器累加成功  
  21.         while(lock->write) {  
  22.             __sync_synchronize();  
  23.         }  
  24.         __sync_add_and_fetch(&lock->read,1);  
  25.         if (lock->write) {//当已是写锁时,则去掉读锁记数器  
  26.             __sync_sub_and_fetch(&lock->read,1);  
  27.         } else {  
  28.             break;  
  29.         }  
  30.     }  
  31. }  
  32.   
  33. static inline void  
  34. rwlock_wlock(struct rwlock *lock) {  
  35.     __sync_lock_test_and_set(&lock->write,1);  
  36.     while(lock->read) {  
  37.         //http://blog.itmem.com/?m=201204  
  38.         //http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Atomic-Builtins.html  
  39.         __sync_synchronize();//很重要,如果去掉,g++ -O3 优化编译后的生成的程序会产生死锁  
  40.     }  
  41. }  
  42.   
  43. static inline void  
  44. rwlock_wunlock(struct rwlock *lock) {  
  45.     __sync_lock_release(&lock->write);  
  46. }  
  47.   
  48. static inline void  
  49. rwlock_runlock(struct rwlock *lock) {  
  50.     __sync_sub_and_fetch(&lock->read,1);  
  51. }  



    这里并未使用pthread_mutex_t来设计锁,而是使用了__sync_fetch_and_add指令体系,而相关内容可以参见这个链接:
    http://soft.chinabyte.com/os/412/12200912.shtml

    当然最终是否如上面链接中作者所说的比pthread_mutex_t性能要高7-8倍,我没测试过,感兴趣的朋友也可以帮助测试一下。

    有了这两个类之后,我又补充了原文作者中所提到了KEY比较方法的定义,同时引入了id来支持object-c的对象缓存,最终代码修改如下:

[cpp]  view plain copy
  1. #ifndef _MAP_LRU_CACHE_H_  
  2. #define _MAP_LRU_CACHE_H_  
  3.   
  4. #include <string.h>  
  5. #include <iostream>  
  6. #include "rwlock.h"  
  7. #include <stdio.h>  
  8. #include <sys/malloc.h>  
  9. using namespace std;  
  10.   
  11. namespace lru_cache {  
  12.      
  13. static const int DEF_CAPACITY = 100000;//默认缓存记录数  
  14.   
  15. typedef unsigned long long virtual_time;  
  16.   
  17. typedef struct _HashKey  
  18. {  
  19.     NSString* key;  
  20. }HashKey;  
  21.      
  22. typedef struct _HashValue  
  23. {  
  24.     id value_;  
  25.     virtual_time access_;  
  26. }HashValue;  
  27.   
  28. //仅针对HashKey比较器  
  29. template <class key_t>  
  30. struct hashkey_compare{  
  31.     bool operator()(key_t x, key_t y) const{  
  32.         return x < y;  
  33.     }  
  34. };  
  35.          
  36. template <>  
  37. struct hashkey_compare<HashKey>  
  38. {  
  39.     bool operator()(HashKey __x, HashKey __y) const{  
  40.         string x = [__x.key UTF8String];  
  41.         string y = [__y.key UTF8String];  
  42.         return x < y;  
  43.     }  
  44. };  
  45.          
  46. //自定义map类型  
  47. template <typename K, typename V, typename _Compare = hashkey_compare<K>,  
  48. typename _Alloc = std::allocator<std::pair<const K, V> > >  
  49. class  lru_map: public map<K, V, _Compare, _Alloc>{};  
  50.              
  51. class CLRUCache  
  52. {  
  53. public:  
  54.      
  55.     CLRUCache() : _now(0){  
  56.         _lru_list = shared_ptr<lru_map<virtual_time, HashKey> >(new lru_map<virtual_time, HashKey>);  
  57.         _hash_table = shared_ptr<lru_map<HashKey, HashValue> > (new lru_map<HashKey, HashValue>);  
  58.     }  
  59.      
  60.     ~CLRUCache(){  
  61.         _lru_list->clear();  
  62.         _hash_table->clear();  
  63.     }  
  64.      
  65.     int set( const HashKey& key, const id &value )  
  66.     {  
  67.         HashValue hash_value;  
  68.         hash_value.value_ = value;  
  69.         hash_value.access_ = get_virtual_time();  
  70.         pair< map<HashKey, HashValue>::iterator, bool > ret = _hash_table->insert(make_pair(key, hash_value));  
  71.         if ( !ret.second ){  
  72.             // key already exist  
  73.             virtual_time old_access = (*_hash_table)[key].access_;  
  74.             map<virtual_time, HashKey>::iterator iter = _lru_list->find(old_access);  
  75.             if(iter != _lru_list->end())  
  76.             {  
  77.                 _lru_list->erase(iter);  
  78.             }  
  79.             _lru_list->insert(make_pair(hash_value.access_, key));  
  80.             (*_hash_table)[key] = hash_value;  
  81.         }         
  82.         else {  
  83.             _lru_list->insert(make_pair(hash_value.access_, key));  
  84.              
  85.             if ( _hash_table->size() > DEF_CAPACITY )  
  86.             {  
  87.                 // get the least recently used key  
  88.                 map<virtual_time, HashKey>::iterator iter = _lru_list->begin();  
  89.                 _hash_table->erase( iter->second );  
  90.                 // remove last key from list  
  91.                 _lru_list->erase(iter);  
  92.             }  
  93.         }  
  94.         return 0;  
  95.     }  
  96.      
  97.     HashValue* get( const HashKey& key )  
  98.     {  
  99.         map<HashKey, HashValue>::iterator iter = _hash_table->find(key);  
  100.         if ( iter != _hash_table->end() )  
  101.         {  
  102.             virtual_time old_access = iter->second.access_;  
  103.             iter->second.access_ = get_virtual_time();  
  104.             //调整当前key在LRU列表中的位置  
  105.             map<virtual_time, HashKey>::iterator it = _lru_list->find(old_access);  
  106.             if(it != _lru_list->end()) {  
  107.                 _lru_list->erase(it);  
  108.             }  
  109.             _lru_list->insert(make_pair(iter->second.access_, key));  
  110.             return &(iter->second);  
  111.         }  
  112.         else{  
  113.             return NULL;  
  114.         }  
  115.     }  
  116.      
  117.      
  118.     unsigned get_lru_list_size(){ return (unsigned)_lru_list->size(); }  
  119.     unsigned get_hash_table_size() { return (unsigned)_hash_table->size(); }  
  120.     virtual_time get_now() { return _now; }  
  121.      
  122. private:  
  123.     virtual_time get_virtual_time()  
  124.     {  
  125.         return ++_now;  
  126.     }  
  127.      
  128.     shared_ptr<lru_map<virtual_time, HashKey> >    _lru_list;  
  129.     shared_ptr<lru_map<HashKey, HashValue> > _hash_table;  
  130.     virtual_time _now;  
  131. };  
  132.      
  133. #endif  




      接下来看一下如果结合单例和rwlock来设计最终的缓存功能,如下:

[cpp]  view plain copy
  1. using namespace lru_cache;  
  2. class DZCache: public Singlton<DZCache>  
  3. {  
  4.     friend  class Singlton<DZCache>;  
  5. private:  
  6.     shared_ptr<CLRUCache> clu_cache;  
  7.     rwlock *lock;  
  8.     DZCache(){  
  9.         lock =(rwlock*) malloc(sizeof(rwlock));  
  10.         rwlock_init(lock);  
  11.         clu_cache = shared_ptr<CLRUCache>(new CLRUCache());  
  12.         cout << "construct JobList" << endl;  
  13.     }  
  14.      
  15.     DZCache * Instance() {  
  16.         return s_instance.get();  
  17.     }  
  18.   
  19. public:  
  20.      
  21.     ~DZCache(){  
  22.         free(lock);  
  23.     }  
  24.      
  25.     static DZCache& getInstance(){  
  26.         return *instance();  
  27.     }  
  28.   
  29.     void set(NSString* key, id value){  
  30.         //加锁  
  31.         rwlock_wlock(lock);  
  32.         HashKey hash_key;  
  33.         hash_key.key = key;  
  34.         clu_cache->set(hash_key, value);  
  35.         rwlock_wunlock(lock);  
  36.     }  
  37.      
  38.     id get(NSString* key){  
  39.         HashKey hash_key;  
  40.         hash_key.key = key;  
  41.         HashValue* value = clu_cache->get(hash_key);  
  42.         if(value == NULL){  
  43.             return nil;  
  44.         }  
  45.         else{  
  46.             return value->value_;  
  47.         }  
  48.     }  
  49. };  
  50.   
  51. #endif  




    最后看一下如何使用:
[cpp]  view plain copy
  1. void testLRUCache(){  
  2.     //指针方式  
  3.     DZCache::instance()->set(@"name", @"daizhj");//设置  
  4.     NSString* name = (NSString*)DZCache::instance()->get(@"name");//获取  
  5.     std::cout<<[name UTF8String]<<endl;  
  6.      
  7.     NSNumber * age=[NSNumber numberWithInt:123123];  
  8.     DZCache::instance()->set(@"age", age);  
  9.     age = (NSNumber*)DZCache::instance()->get(@"age");  
  10.   
  11.     //对象方式  
  12.     DZCache::getInstance().set(@"name", @"daizhenjun");  
  13.     name = (NSString*)DZCache::getInstance().get(@"name");  
  14.     std::cout<<[name UTF8String]<<endl;  
  15.      
  16.     age = [NSNumber numberWithInt:123456];  
  17.     DZCache::getInstance().set(@"age", age);  
  18.     age = (NSNumber*)DZCache::getInstance().get(@"age");  
  19. }  




    好了,今天的内容就先到这里了。

    原文链接: http://www.cnblogs.com/daizhj/archive/2012/11/13/2768092.html
    作者: daizhj, 代震军 
    微博: http://weibo.com/daizhj
    Tags:ios, c++, lru, cache, map

这篇关于当C++遇到IOS应用开发---LRUCache缓存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/416118

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

hdu1394(线段树点更新的应用)

题意:求一个序列经过一定的操作得到的序列的最小逆序数 这题会用到逆序数的一个性质,在0到n-1这些数字组成的乱序排列,将第一个数字A移到最后一位,得到的逆序数为res-a+(n-a-1) 知道上面的知识点后,可以用暴力来解 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#in

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof