web-dev-qa-db-ja.com

C ++(unordered_mapおよびLinkedlist)を使用して「マルチスレッド」LRUキャッシュをどのように設計しますか?

これはスレッドセーフなLRUキャッシュに関するものであることに注意してください( https://leetcode.com/problems/lru-cache/description/ で指定されている単なるLRUキャッシュではありません)。他のマルチスレッドLRU設計の質問では扱われていないLocking Hashtable/Linkedlist(LL)のトリッキーな側面があるため、これはLRUキャッシュ設計の質問の複製ではありません。

C++でLRUキャッシュをスレッドセーフにする方法については、広く認められているアプローチのようです。 Hashtable/LLの両方をロックしても問題ないというリンクに気づきましたが、C++の問題に直接対処せず、さまざまな方法で漠然と議論しているリンクもあります。

  • ロックされているものを含むロックを使用して、マルチスレッドバージョンを実装するときに、誰かが機能的かつ効率的なアプローチを説明できますかC++のLRUキャッシュの例 https://leetcode.com/problems/lru-cache/description/ したがって、すべてのget/set操作はO(1)?

  • facebookのmemcachedなどのキャッシュは、マルチスレッドサポートをどのように実装しますか?

4
Joe Black

複数のリーダー/単一のライター ロックを使用してこれを実装しました。これは、複数のスレッドが同時にキャッシュから読み取ることができるタイプのロックですが、単一のスレッドのみがキャッシュに書き込むことができます。基本的な要点は次のようなものです(擬似コード):

void put(ItemType item, KeyType key)
{
    cacheLock.lockForWriting();

    // If it is already in the list and map remove it
    list.remove(key);
    map.remove(key);

    // Now put it back into both
    map [ key ] = item;
    list.append(key);

    // If we're past the size limit of the cache, remove the least recently used item
    if (list.size() > MAX_CACHE_SIZE)
    {
        ListNode *oldKey = list.head;
        list.head = list.head.next;
        map.remove(oldKey->key);
        delete oldKey;
    }

    cacheLock.unlock();
}

ItemType* get(KeyType key)
{
    cacheLock.lockForReading();
    ItemType* item  = map [ key ];
    cacheLock.unlock();

    // NOTE: This assumes that the cache is not the owner of this object
    // If it is, then you need to either make a copy of it inside the lock 
    // above or use smart pointers instead of raw  pointers
    // because when it gets kicked out of the cache it will be deleted.
    return item;
}
4
user1118321