【发布时间】:2014-03-25 22:00:33
【问题描述】:
我目前有一个具有类似缓存机制的程序。我有一个线程正在侦听从另一台服务器到此缓存的更新。该线程将在收到更新时更新缓存。这是一些伪代码:
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 而不是一个 unique_ptr 用于 cache_。当所有线程都使用 cache_ 完成时,shared_ptr 应该自行删除。
关于我的程序的一点点:我的程序是一个网络服务器,它将使用这些信息来决定返回什么信息。这是相当高的吞吐量(数千个请求/秒)每个请求都会查询一次缓存,因此告诉我的其他线程何时更新是没有问题的。我可以容忍稍微过时的信息,并且如果可能的话,我更愿意阻止我的所有线程执行。缓存中的信息相当大,因此我想限制任何副本的值。
update_cache 只运行一次。它在只监听更新命令并运行代码的线程中运行。
【问题讨论】:
-
使用readers-writer lock。 Boost provides one。同样,您可以使用来自here 的 RCU 的相同建议也适用。
-
这是绝对可行的,但是,如果可能的话,我想避免阻塞。使用唯一指针会导致某种未定义的行为吗?为什么读/写锁是更好的解决方案?另外请注意,我可以容忍稍微过时的信息。
-
我想我的疑虑实际上与设计有关,而不是与实现有关。首先,
unique_ptr似乎不起作用,因为只有一个线程可以合法地持有unique_ptr,这会破坏多个线程访问缓存。即使您可以解决这个问题,客户端线程如何知道它们需要更新?我觉得您的缓存应该公开一个接口,而不仅仅是将实际的缓存指针转储到客户端并让它们疯狂运行。如果您可以让客户端查询缓存,那么类似 RCU 的方法可能是完美的——零开销读取! -
哎呀,对不起,我的错误。我相信我的意思是
shared_ptr不是unique_ptr。我对我的原始帖子进行了一些更新,以更好地描述我的程序。我查询缓存的线程不需要知道缓存何时更新,它们正在处理 Web 请求,并且将使用提供的任何信息。我可以提供一个接口,但是数据集很大,我必须通过引用传递才能有效。所以我想要某种智能指针来处理我正在使用的任何数据(无论是值上的 smart_ptr 并传递它,还是地图上的 smart_ptr。
标签: c++ multithreading c++11 shared-ptr