#include "iostream"
#include "map"
#include "list"
#include "mutex"
#include "condition_variable"
#include "unordered_map"
using namespace std;
//线程安全的sharedLRU
template <class Key, class Value, class C = std::less<Key>, class Hash = std::hash<Key> >
class SharedLRU
{
using VPtr = std::shared_ptr<Value>;//智能指针,对于非基本类型,可以自己析构,
using WeakPtr = std::weak_ptr<Value>;//防止交叉引用
mutex lock;//加锁,线程安全
size_t max_size;
condition_variable cv;//条件变量,通知事件
unsigned int size;
public:
int waiting;
private:
//using iter = list<pair<Key, VPtr>>::iterator;
unordered_map<Key, typename list<pair<Key, VPtr>>::iterator, Hash> contents;//实际底层是hasH,每个key_index
list<pair<Key, VPtr>> lru;//缓存对象,每个key_value以双向链表形式存储
map<Key, pair<WeakPtr, Value*>, C> weak_refs;//避免交叉引用时存在的风险
private:
//超过容量时,清楚缓存
void trim_cache(list<VPtr> *to_release)
{
while (size > max_size)
{
to_release->push_back(lru.back().second);//list最后面,代表最不经常被访问
lru_remove(lru.back().first);
}
}
void lru_remove(const Key& key)
{
auto iter = contents.find(key);
if(iter != contents.end())
{
lru.erase(iter->second);
--size;
contents.erase(iter);
}
}
void lru_add(const Key& key, const VPtr& val, list<VPtr> *to_release)
{
auto i = contents.find(key);
if(i != contents.end())
{
lru.splice(lru.begin(), lru, i->second);
}
else
{
++size;
lru.push_front(make_pair(key,val));
contents[key] = lru.begin();
trim_cache(to_release);
}
}
void remove(const Key& key, VPtr *valptr)
{
lock.lock();
auto iter = weak_refs.find(key);
if(iter != weak_refs.end() and iter->second.second ==valptr)
{
weak_refs.erase(iter);
}
lock.unlock();
cv.notify_all();
}
public:
SharedLRU(size_t max_size = 20):lock(),max_size(max_size),size(0),waiting(0)
{
contents.rehash(max_size);
}
~SharedLRU()
{
contents.clear();
lru.clear();
if(!weak_refs.empty())
{
cout << "leaked refs"<<endl;
}
}
void clear()
{
while (true)
{
VPtr val;
lock.lock();
if(size == 0)
{
break;
}
val = lru.back().second;
lru_remove(lru.back().first);
lock.unlock();
}
}
void clear(const Key& key)
{
VPtr val;
{
lock.lock();
auto iter = weak_refs.find(key);
if(iter != weak_refs.end())
{
val = iter->second.first.lock();
}
lru_remove(key);
lock.unlock();
}
}
void purge(const Key& key)
{
VPtr val;
{
lock.lock();
auto iter = weak_refs.find(key);
if(iter != weak_refs.end())
{
val = iter->second.first.lock();
weak_refs.erase(iter);
}
lru_remove(key);
lock.unlock();
}
}
void set_size(size_t new_size)
{
list<VPtr> to_release;
lock.lock();
max_size = new_size;
trim_cache(&to_release);
}
Key cache_key_low_bound()
{
return weak_refs.begin()->first;
}
VPtr lower_bound(const Key& key)
{
VPtr val;
list<VPtr> to_release;
{
lock.lock();
++waiting;
bool retry = false;
do
{
retry = false;
if(weak_refs.empty())
{
break;
}
auto i = weak_refs.lower_bound(key);
if(i == weak_refs.end())
{
--i;
}
else
{
val = i->second.first.lock();
}
if(val)
{
lru_add(i->first, val, &to_release);
}
else
{
retry = true;
}
if(retry)
{
//cv.wait(lock,[]{return retry;});
}
}while(retry);
--waiting;
lock.unlock();
}
return val;
}
bool empty()
{
return weak_refs.empty();
}
VPtr add(const Key& key, Value *value, bool *existed = NULL)
{
VPtr val;
list<VPtr> to_release;
{
auto actual = weak_refs.lower_bound(key);
if (actual != weak_refs.end() && actual->first == key)
{
if (existed)
*existed = true;
return actual->second.first.lock();
}
if (existed)
*existed = false;
val = VPtr(value);
weak_refs.insert(actual, make_pair(key, make_pair(val, value)));
lru_add(key, val, &to_release);
}
return val;
}
};
int main()
{
SharedLRU<int,int> demo;
unsigned int key = 1;
int value1 = 2;
bool existed = false;
auto ptr = demo.add(key, new int(value1), &existed);
cout << *ptr << endl;
cout << existed <<endl;
cout << demo.cache_key_low_bound() <<endl;
demo.clear();
cout << demo.empty()<<endl;
getchar();
return 0;
}
C++ 实现shareLRU
最新推荐文章于 2023-12-03 17:18:12 发布