3. LruCache
使用下述功能需要包含头文件coke/lru_cache.h。
coke::LruCache¶
LruCache是一个基于LRU淘汰策略的并发安全的缓存容器,支持异步等待缓存就绪。适用于需要缓存热点数据且需要协调多个协程访问同一资源的场景。
template<typename K, typename V, typename H = std::hash<K>,
typename E = std::equal_to<>>
class LruCache;
LruCache使用哈希表管理数据,默认使用std::hash<K>计算key的哈希值,使用std::equal_to<void>比较两个key是否等价。
成员类型¶
using Key = K;
using Value = V;
using Hash = H;
using Equal = E;
using Entry = detail::LruEntry<K, V>;
using Handle = detail::LruHandle<K, V>;
using SizeType = std::size_t;
成员函数¶
-
构造函数
创建指定容量的
LruCache。若max_size为0则转换为SizeType(-1)。explicit LruCache(SizeType max_size = 0, const Hash &hash = Hash(), const Equal &equal = Equal());LruCache不可移动、不可复制。LruCache(LruCache &&) = delete; LruCache &operator=(LruCache &&) = delete; LruCache(const LruCache &) = delete; LruCache &operator=(const LruCache &) = delete; -
析构函数
销毁
LruCache,应保证所有通过get_or_create返回的handle都不再处于等待状态。~LruCache(); -
容量查询
// 获取当前缓存的条目数 SizeType size() const; // 获取构造时传入的缓存容量 SizeType capacity() const; -
获取条目
通过键查找条目,返回空
handle表示未命中。命中时会自动将key升热。template<typename U> requires HashEqualComparable<Hash, Equal, Key, U> Handle get(const U &key); -
获取或创建条目
返回
(handle, created)对。当created为true时,调用者应负责填充值并唤醒等待者。template<typename U> requires (HashEqualComparable<Hash, Equal, Key, U> && std::constructible_from<Key, const U &>) [[nodiscard]] std::pair<Handle, bool> get_or_create(const U &key); -
插入条目
直接插入条目,使用
args...构造value,并返回对应handle。若key存在则会被覆盖,此前已经获取的与旧值关联的handle仍能访问旧的值。template<typename U, typename... Args> requires (HashEqualComparable<Hash, Equal, Key, const U &> && std::constructible_from<Key, const U &> && std::constructible_from<Value, Args && ...>) Handle put(const U &key, Args &&...args); -
删除条目
支持通过键或
handle删除。条目会立即被移除,但此前已经获取的handle仍可使用。template<typename U> requires HashEqualComparable<Hash, Equal, Key, const U &> void remove(const U &key); void remove(const Handle &handle); -
清空缓存
void clear();
coke::detail::LruHandle¶
-
构造、赋值、析构函数
// 创建一个空LruHandle,不关联任何条目。 LruHandle() noexcept; // 复制构造,创建一个新的LruHandle,关联同一个条目。 LruHandle(const LruHandle &) noexcept; // 移动构造 LruHandle(LruHandle &&) noexcept; // 复制赋值,关联同一个条目。 LruHandle &operator=(const LruHandle &) noexcept; // 移动赋值 LruHandle &operator=(LruHandle &&) noexcept; // 析构函数,自动释放关联的条目。 ~LruHandle(); -
状态检查
// 是否关联条目 operator bool() const noexcept; // 是否正在等待值 bool waiting() const noexcept; // 是否成功设置值 bool success() const noexcept; // 是否标记为失败 bool failed() const noexcept; -
值操作
填充值或标记失败状态后,均需要调用
notify_one/notify_all唤醒等待者。// 原地构造值 template<typename... Args> void emplace_value(Args &&...args) // 通过回调函数设置值 template<typename ValueCreater> void create_value(ValueCreater &&creater) // 标记为失败状态 void set_failed(); -
异步等待
协程返回一个
int类型整数,有以下几种情况coke::TOP_SUCCESS表示成功取出coke::TOP_TIMEOUT表示等待超时,wait_for可能返回该值coke::TOP_ABORTED表示进程正在退出coke::TOP_CLOSED表示容器为空且已被关闭- 负数表示发生系统错误,该情况几乎不会发生
// 等待至状态变化 Task<int> wait(); // 带超时的等待 Task<int> wait_for(coke::NanoSec nsec); -
唤醒机制
// 唤醒单个等待协程 void notify_one(); // 唤醒所有等待协程 void notify_all(); -
获取值
// 获取key const Key &key() const noexcept; // 获取value,要求此时处于成功状态 const Value &value() const noexcept; // 获取可修改的value,要求此时处于成功状态。使用者保证后续对value的修改是线程安全的。 Value &mutable_value() noexcept;
示例¶
参考example/ex018-lru_cache.cpp。