1
\$\begingroup\$

I am learning concurrent programming and am writing a thread safe LRU cache for practice. Below is my first attempt. Kindly comment and let me know where I can improve.

PS: There have already been a few questions asked on this topic but a more toned down version will help me understand the underlying concept of concurrency.

#include "stdafx.h"
#include <iostream>
#include <unordered_map>
#include "thread"
#include "mutex"

class LRUCache
{

    std::mutex mu;

private:
    int cacheSize;
    std::unordered_map<int, std::pair<int, std::list<int>::iterator>> cache;
    std::list<int> lru;
    void update(std::unordered_map<int, std::pair<int, std::list<int>::iterator>>::iterator &it);

public:
    void setSize(int size);
    int get(int key);
    void set(int key, int value);
};

void LRUCache::setSize(int size)
{
    std::lock_guard <std::mutex> locker(mu);
    cacheSize = size;
}

int LRUCache::get(int key)
{
    std::lock_guard <std::mutex> locker(mu);
    auto item = cache.find(key);

    if (item == cache.end())
    {
        return -1;
    }

    update(item);

    return item->second.first;
}

void LRUCache::set(int key, int value)
{
    std::lock_guard <std::mutex> locker(mu);

    auto item = cache.find(key);

    if (item != cache.end())
    {
        update(item);
        cache[key] = { value, lru.begin() };
        return;
    }

    if (cache.size() == cacheSize)
    {
        cache.erase(lru.back());
        lru.pop_back();
    }

    lru.push_front(key);
    cache.insert({ key,{ value, lru.begin() } });
}

void LRUCache::update(std::unordered_map<int, std::pair<int, std::list<int>::iterator>>::iterator &it)
{
    lru.erase(it->second.second);
    lru.push_front(it->first);
    it->second.second = lru.begin();
}

void function2(LRUCache *lruCache)
{
    lruCache->set(5, 5);
    lruCache->set(6, 6);
    lruCache->set(1, 1);

    std::cout << "F2::Successful Execution: " << lruCache->get(4) << std::endl;

    lruCache->set(8, 8);

    std::cout << "F2::Successful Execution: " << lruCache->get(1) << std::endl;
}

void function1(LRUCache *lruCache)
{
    lruCache->set(1, 1);
    lruCache->set(2, 2);
    lruCache->set(3, 3);

    std::cout << "F1::Successful Execution: " << lruCache->get(3) << std::endl;

    lruCache->set(4, 4);

    std::cout << "F1::Successful Execution: " << lruCache->get(2) << std::endl;
}

int main() {

    LRUCache *lruCache = new LRUCache();
    lruCache->setSize(2);

    std::thread t1(function1, lruCache);
    t1.join();

    std::thread t2(function2, lruCache);
    t2.join();

    return 0;
}
\$\endgroup\$
  • \$\begingroup\$ What part, exactly, is "toned down"? Do you mean that you want the answers to be toned down in terms of their complexity? If so, you might consider indicating that by adding the [beginner] tag. Or maybe you just mean that your code/implementation is simpler than the other questions? (Also, please don't use blockquotes to quote yourself!) \$\endgroup\$ – Cody Gray Jan 5 '17 at 11:10
  • \$\begingroup\$ The latter, simpler code implementations \$\endgroup\$ – tamraj_kilvish Jan 5 '17 at 14:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.