代码之家  ›  专栏  ›  技术社区  ›  Soleil

这是Cache线程安全(C++)的通用实现吗?

  •  0
  • Soleil  · 技术社区  · 6 年前

    我编写了以下通用缓存的实现,其中 func 将提供值(计算、读取文件等)。 它是线程安全的吗?

    #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();
    }
    

    编辑:对于上下文,我将使用此类添加此条件:

    对于给定的键,该值始终相同

    我不应该只在我 insert ?在插入的同时读取存储在映射中的某个键值可以吗?让两个线程同时进行插入是否也可以(这样我就可以避免使用互斥体)?

    我从Butenhoff的书中了解到,我们只需要在修改数据时使用mutex。因此,在一个映射中,由于对于一个给定的键,指向该值的指针总是相同的(这要归功于散列函数),因此如果该键存在,我不需要锁定。

    1 回复  |  直到 6 年前
        1
  •  6
  •   Sam Varshavchik    6 年前

    由于多种原因,此实现不是线程安全的。

    前半部分 GetOf() 调用的方法 std::map 的例子。都不 STD::地图 的方法是线程安全的,而 GETFF() 修改 STD::地图 .

    因为互斥不保护前半部分 Getof() 在调用上述方法的地方,这不是线程安全的。

    Clear() 同时修改 STD::地图 ,也没有任何同步/互斥保护。

    P.S.调用 std::map::clear() 在析构函数中是不必要的。