C++ 实现shareLRU

17 篇文章 1 订阅
#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值