c++ thread safe lru cache

it2023-09-25  73

c++ thread safe lru cache

c++ 实现的线程安全的lru cache,支持时间过期和gc

#ifndef PERSONAL_THREAD_SAFE_LRU_CACHE_H #define PERSONAL_THREAD_SAFE_LRU_CACHE_H #include "boost/thread/locks.hpp" #include "boost/thread/shared_mutex.hpp" #include <cstdint> #include <iostream> #include <list> #include <mutex> #include <pthread.h> #include <unistd.h> #include <unordered_map> namespace personal { namespace lru { typedef ::boost::shared_lock<::boost::shared_mutex> ReadLock; typedef ::boost::unique_lock<::boost::shared_mutex> WriteLock; template <typename key_t, typename value_t> class LRUCache { public: struct Item { Item(const value_t &v) : val(v) { insert_time = std::time(nullptr); } value_t val; time_t insert_time; }; typedef typename std::pair<key_t, Item> k_v_pair_t; typedef typename std::list<k_v_pair_t>::iterator list_iterator_t; public: LRUCache(uint32_t max_size, uint32_t expired_time, uint32_t gc_interval); ~LRUCache(); void put(const key_t &key, const value_t &value); bool get(const key_t &key, value_t &val); void erase(const key_t &key); void clear(); uint32_t size(); uint32_t max_size(); uint32_t get_expired_time(); uint32_t get_gc_interval(); uint32_t get_gc_flag(); ::boost::shared_mutex &get_mutex(); private: uint32_t _max_size; uint32_t _expired_time; uint32_t _gc_interval; uint32_t _cur_size; pthread_t _gc_thread; uint32_t _gc_flag; ::boost::shared_mutex _rw_mutex; std::list<k_v_pair_t> _cache_list; std::unordered_map<key_t, list_iterator_t> _cache_map; private: static void *_gc(void *arg); void _stop(); }; //*********line*********** template <typename key_t, typename value_t> void *LRUCache<key_t, value_t>::_gc(void *arg) { int gc_num = 0; LRUCache<key_t, value_t> *ptr = static_cast<LRUCache<key_t, value_t> *>(arg); uint32_t gc_flag = ptr->get_gc_flag(); uint32_t gc_interval = ptr->get_gc_interval(); uint32_t expired_time = ptr->get_expired_time(); ::boost::shared_mutex &rw_mutex = ptr->get_mutex(); while (gc_flag) { uint32_t now_time = std::time(nullptr); { gc_num++; int gc_count = 0; WriteLock wlock(rw_mutex); auto begin = ptr->_cache_map.begin(); while (begin != ptr->_cache_map.end()) { uint32_t insert_time = begin->second->second.insert_time; if (now_time - insert_time >= expired_time) { ptr->_cache_list.erase(begin->second); begin = ptr->_cache_map.erase(begin); gc_count++; } else { ++begin; } } std::cout << "gc_num[" << gc_num << "] gc_count[" << gc_count << "]" << std::endl; } sleep(gc_interval); gc_flag = ptr->get_gc_flag(); gc_interval = ptr->get_gc_interval(); expired_time = ptr->get_expired_time(); } return nullptr; } template <typename key_t, typename value_t> LRUCache<key_t, value_t>::LRUCache(uint32_t max_size, uint32_t expired_time, uint32_t gc_interval) : _max_size(max_size), _expired_time(expired_time), _gc_interval(gc_interval) { _gc_flag = 1; pthread_create(&_gc_thread, nullptr, _gc, static_cast<void *>(this)); } template <typename key_t, typename value_t> LRUCache<key_t, value_t>::~LRUCache() { _stop(); pthread_join(_gc_thread, nullptr); } template <typename key_t, typename value_t> void LRUCache<key_t, value_t>::put(const key_t &key, const value_t &value) { WriteLock wlock(_rw_mutex); auto it = _cache_map.find(key); _cache_list.push_front(k_v_pair_t(key, Item(value))); if (it != _cache_map.end()) { _cache_list.erase(it->second); _cache_map.erase(it); } _cache_map.insert(std::make_pair(key, _cache_list.begin())); if (_cache_map.size() > _max_size) { auto last = _cache_list.end(); last--; _cache_map.erase(last->first); _cache_list.pop_back(); } ++_cur_size; } template <typename key_t, typename value_t> bool LRUCache<key_t, value_t>::get(const key_t &key, value_t &val) { ReadLock rlock(_rw_mutex); auto it = _cache_map.find(key); if (it == _cache_map.end()) { return false; } uint32_t time_now = std::time(nullptr); // expire if (it->second->second.insert_time + _expired_time < time_now) { return false; } _cache_list.splice(_cache_list.begin(), _cache_list, it->second); val = it->second->second.val; return true; } template <typename key_t, typename value_t> void LRUCache<key_t, value_t>::erase(const key_t &key) { WriteLock wlock(_rw_mutex); auto it = _cache_map.find(key); if (it != _cache_map.end()) { _cache_list.erase(it->second); _cache_map.erase(it); --_cur_size; } } template <typename key_t, typename value_t> void LRUCache<key_t, value_t>::clear() { WriteLock wlock(_rw_mutex); _cache_map.clear(); _cache_list.clear(); } template <typename key_t, typename value_t> uint32_t LRUCache<key_t, value_t>::size() { return _cur_size; } template <typename key_t, typename value_t> uint32_t LRUCache<key_t, value_t>::max_size() { return _max_size; } template <typename key_t, typename value_t> uint32_t LRUCache<key_t, value_t>::get_expired_time() { return _expired_time; } template <typename key_t, typename value_t> uint32_t LRUCache<key_t, value_t>::get_gc_interval() { return _gc_interval; } template <typename key_t, typename value_t> uint32_t LRUCache<key_t, value_t>::get_gc_flag() { return _gc_flag; } template <typename key_t, typename value_t> ::boost::shared_mutex &LRUCache<key_t, value_t>::get_mutex() { return _rw_mutex; } template <typename key_t, typename value_t> void LRUCache<key_t, value_t>::_stop() { _gc_flag = 0; } } // namespace lru } // namespace personal #endif
最新回复(0)