当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

相关文章

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案