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.