gpt4 book ai didi

c++ - 无阻塞更新缓存

转载 作者:行者123 更新时间:2023-11-28 00:31:43 25 4
gpt4 key购买 nike

我目前有一个程序具有类似缓存的机制。我有一个线程监听从另一台服务器到这个缓存的更新。该线程将在收到更新时更新缓存。这是一些伪代码:

void cache::update_cache()
{
cache_ = new std::map<std::string, value>();
while(true)
{
if(recv().compare("update") == 0)
{
std::map<std::string, value> *new_info = new std::map<std::string, value>();
std::map<std::string, value> *tmp;
//Get new info, store in new_info
tmp = cache_;
cache_ = new_cache;
delete tmp;
}
}
}

std::map<std::string, value> *cache::get_cache()
{
return cache_;
}

cache_ 正在从许多不同的线程同时读取。我相信如果我的线程之一调用 get_cache(),然后我的缓存更新,然后该线程尝试访问存储的缓存,我会遇到未定义的行为。

我正在寻找一种方法来避免这个问题。我知道我可以使用互斥体,但我宁愿不阻止读取发生,因为它们必须尽可能低延迟,但如果需要,我可以采用这种方式。

我想知道这是否是 unique_ptr 的一个很好的用例。我的理解是否正确,因为如果一个线程调用 get_cache,并且返回一个 unique_ptr 而不是标准指针,一旦所有具有旧版本缓存的线程都完成了它(即离开范围),该对象将被删除。

对于这种情况,使用 unique_ptr 是最好的选择,还是有其他我没有想到的选择?

任何输入将不胜感激。

编辑:

我相信我在 OP 中犯了一个错误。我的意思是使用并传递一个 shared_ptr 而不是 cache_ 的 unique_ptr。当所有线程都使用完 cache_ 时,shared_ptr 应该自行删除。

关于我的程序的一点点:我的程序是一个网络服务器,它将使用这些信息来决定返回什么信息。这是相当高的吞吐量(数千个请求/秒)每个请求查询缓存一次,所以告诉我的其他线程何时更新是没有问题的。我可以容忍稍微过时的信息,如果可能的话,我更愿意阻止我所有的线程执行。缓存中的信息相当大,因此我想限制任何拷贝的值(value)。

update_cache 只运行一次。它在一个线程中运行,该线程仅监听更新命令并运行代码。

最佳答案

我觉得有很多问题:

1) 不要泄漏内存:为此永远不要在代码中使用“delete”并坚持使用 unique_ptr(或在特定情况下使用 shared_ptr)

2) 保护对共享数据的访问,使用锁定(互斥)或无锁机制(std::atomic)

class Cache {
using Map = std::map<std::string, value>();
std::unique_ptr<Map> m_cache;
std::mutex m_cacheLock;
public:

void update_cache()
{
while(true)
{
if(recv().compare("update") == 0)
{
std::unique_ptr<Map> new_info { new Map };
//Get new info, store in new_info
{
std::lock_guard<std::mutex> lock{m_cacheLock};
using std::swap;
swap(m_cache, new_cache);
}
}
}
}

注意:我不喜欢 update_cache() 成为缓存公共(public)接口(interface)的一部分,因为它包含一个无限循环。我可能会用 recv 外部化循环并有一个:

    void update_cache(std::unique_ptr<Map> new_info)
{
{ // This inner brace is not useless, we don't need to keep the lock during deletion
std::lock_guard<std::mutex> lock{m_cacheLock};
using std::swap;
swap(m_cache, new_cache);
}
}

现在对于缓存的读取,使用适当的封装并且不要将指针指向成员映射转义:

    value get(const std::string &key)
{
// lock, fetch, and return.
// Depending on value type, you might want to allocate memory
// before locking
}

如果缓存中不存在该值,则使用此签名必须抛出异常,另一种选择是返回类似 boost::optional 的内容。

总的来说,如果您在锁定部分之外进行代价高昂的操作(例如内存分配),您可以保持较低的延迟(一切都是相对的,我不知道您的用例)。

关于c++ - 无阻塞更新缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22647222/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com