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();
};
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);
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;
}
}
}
#endif
转载请注明原文地址: https://lol.8miu.com/read-9383.html