简体   繁体   中英

Is this generic implementation of cache thread safe (c++)?

I wrote the following implementation of a generic cache, where func will provide the values (compute, read file, etc). Is it thread safe ?

#pragma once
#include "stdafx.h"
#include <map>
#include <functional>
#include <mutex>

using namespace std;

template<class T1, class T2>
class __declspec(dllexport) CacheOf
{
    map<T1, T2> _cache;
    function<T2(T1)> _func;
    mutex CacheMtx;
public:
    CacheOf(function<T2(T1)> func);
    ~CacheOf();
    T2 Get(T1);
    void Clear();
};

template <class T1, class T2>
CacheOf<T1, T2>::CacheOf(std::function<T2(T1)> func)
{
    _func = func;
}

template <class T1, class T2>
CacheOf<T1, T2>::~CacheOf()
{
    _cache.clear();
}

template <class T1, class T2>
auto CacheOf<T1, T2>::Get(T1 key) -> T2
{

    auto it = _cache.find(key);
    T2 value;
    if (it != _cache.end())
    {
        value = it->second;
        return value;
    }
    value = _func(key);
    {
        unique_lock<mutex> cachelock(CacheMtx);
        _cache.insert(pair<T1, T2>(key, value));
    }
    return value;
}

template <class T1, class T2>
auto CacheOf<T1, T2>::Clear() -> void
{
    _cache.clear();
}

EDIT: For the context I'll use this class I add this condition:

for a given key, the value is always the same

Should not I lock only when I insert ? Is it fine to read a certain key-value stored in the map while inserting at the same time ? Is is also fine to have 2 threads doing an insert at the same time (so I can avoid the usage of a mutex) ?

My understanding from Butenhoff's book is that we need to use mutex only when we modify the data. Therefore, in a map, due to the fact that for a given key, the pointer to the value will always be the same (thanks to the hash function), therefore if the key exists, I don't need to lock.

This implementation is not thread-safe, for multiple reasons.

The first half of GetOf() invokes methods of a std::map 's instance. None of std::map 's methods are thread safe, and the second half of GetOf() modifies the std::map .

Since the mutex does not protect the first half of Getof() , where the aforementioned methods get invoked, this is not thread-safe.

Clear() also modifies the std::map , without any synchronization/mutex protection, either.

PS The invocation of std::map::clear() in the destructor is not necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM