c++ - 这是真正具有最小阻塞的线程安全 LRU 缓存设计吗?
问题描述
下面是我一直在研究的具有最小阻塞的 LRU 缓存设计的伪代码。
缓存具有以下特点:
- 它有一个固定的大小
MAX_CACHE_SIZE
- 是LRU
我希望以下条件为真:
- 如果发生缓存未命中,则在数据可用时不会发生阻塞(在这种情况下是下载的)
- 两次并发缓存未命中后,数据未检索两次
下面是 psudocode 函数getData(name)
,它根据数据的名称从缓存中返回数据。这种设计看起来安全吗?如果没有,如何改进?
storage : dequeue<data> // container for the cache data
lookupmap : map<string, dequeue::iterator> // lookup map with name of data and position in storage dequeue
data getData(name) {
lock()
item_iterator : dequeue::iterator
item_iterator = lookupmap[name]
// if item name is present in the lookup map
if(item_iterator != null) {
// unlocks and waits while item is being downloaded. Still a cache miss,
// but not this threads responsibility to get the data therefore wait for it to be downloaded
cond_var.wait({return item_iterator.item.isDownloaded})
// this removes the item from the queue and adds it to the front, essentially "bumping" it
item : data
item = item_iterator.item
storage.remove(item_iterator)
storage.push_front(item)
lookupmap[name] = storage.begin()
unlock()
return item
} else {
// registers that item name but initialises it as null to indicate not downloaded yet
lookupmap[name] = null
unlock() // unlocks so that other threads can proceed while peforming download
item : data
item = downloadItem(name)
lock() // locks again once downloaded
// removes last item in cache if storage is full (LRU)
if(storage.size() == MAX_CACHE_SIZE) {
tempitem : data
tempitem = storage.back()
storage.pop_back()
lookupmap.remove(tempItem.name)
}
// registers new item in cache
storage.push_front(item)
lookupMap[dataname] = storage.begin()
unlock()
cv.notify_all() // notifies any waiting threads that a item has now been downloaded
return item
}
}
编辑:
不确定这是否是一个问题,但只是为了澄清 - 此设计有一个全局互斥锁和一个全局条件变量。
解决方案
伪代码没有描述线程安全算法。
考虑到多个线程可能正在等待一个特定项目被完全下载。他们每个人都将持有(在堆栈内存中)相同的 item_iterator。下载完成。当第一个等待线程唤醒时,为了维护 LRU,它将使仍然被其他线程持有的迭代器失效。
(我想到的另一个问题是可以的,只要参与线程的最大数量小于 MAX_CACHE_SIZE。)
醒来后查找新的 item_iterator 是否足够修复?也许吧,但令人担忧的是,当线程在各种状态下处于活动状态时,共享的主要数据结构(存储本身)经常发生变化。这不是一个健壮的设计。
我会考虑保持存储稳定并以不同的方式评估 LRU。
推荐阅读
- api - 颤动的http post请求显示状态码500,尽管它在邮递员中工作
- java - 将时区字符串日期解析为 Java 的 Instant
- node.js - 我如何将(例如!lang en)保存到 json 文件中,以便机器人使用该 lang 的差异命令
- rest - 如何使用 apollo 客户端进行休息发布请求?
- android - Android ContentResolver 正在从选择中返回具有不同 mime 类型的文件
- r - 如何应用用户定义的函数来获取 ParalleDisr 中的距离
- null - .withSuccessHandler 返回 null
- python - 如何从路径的用户那里获取输入,我必须将多个 excel 文件头和文件名合并到 python 中的其他 excel 文件中
- javascript - JavaScript Promise 构造函数
- ruby-on-rails - 受保护的 state_machines 事件