如何实现线程安全的LRU缓存驱逐?

时间:2015-10-12 19:47:40

标签: c++ multithreading caching lru

我已经实现了LRU缓存(code),我希望将其用于具有N个元素和完整N ^ 2(所有对)匹配的多线程匹配问题。理想情况下,我只是直接从缓存中获取对每个元素的引用以节省内存。

匹配两个元素(让它们称为A和B)的时间可以大大改变,我担心如果一对元素需要很长时间来匹配另一个线程(这是非常快速和处理许多对)将导致A或B从缓存中逐出,使引用无效。

一个简单的解决方案就是不使用引用,但我想知道是否有更好的方法可以确保元素不会被驱逐,如果它们是"目前使用的"或者引用它们?

1 个答案:

答案 0 :(得分:1)

为避免驱逐正在使用的对象,可以使用std::shared_ptr的引用计数功能。请考虑以下实现:

#include <iostream>
#include <string>
#include <memory>
#include <map>
#include <algorithm>

template <typename K, typename V> class cache
{
public:
    cache() {}

    static const constexpr int max_cache_size = 2;

    std::shared_ptr<V> getValue(const K& k)
    {
        auto iter = cached_values.find(k);
        if (iter == cached_values.end()) {

            if (cached_values.size() == max_cache_size) {
                auto evictIter =
                    std::find_if(cached_values.begin(), cached_values.end(),
                        [](const auto& kv) { return kv.second.second.unique(); });

                if (evictIter == cached_values.end()) {
                    std::cout << "Nothing to evict\n";
                    return nullptr;
                }

                cached_values.erase(evictIter);
            }

            static V next;

            iter = cached_values.insert(std::make_pair(k, std::make_pair(++next, nullptr))).first;
            iter->second.second = std::shared_ptr<V>(&iter->second.first, [](const auto&) {});
        }

        return iter->second.second;
    }

    std::map<K, std::pair<V, std::shared_ptr<V>>> cached_values;
};

int main()
{
    cache<int, int> c;

    std::cout << *c.getValue(10) << "\n";
    std::cout << *c.getValue(20) << "\n";
    std::cout << *c.getValue(30) << "\n";

    auto useOne = c.getValue(10);
    auto useTwo = c.getValue(20);
    std::cout << *c.getValue(20) << "\n"; // We can use stuff that is still in cache
    std::cout << c.getValue(30);          // Cache is full, also note no dereferencing
}

基本上,只要缓存外的任何人都使用返回的值,std::shared_ptr::unique将返回false,使缓存条目不可删除。

Live example