我希望实现一个具有 2 个写入器和多个读取器的简单结构映射。为了使它线程安全,我目前正在使用带有唯一锁的互斥锁(我的代码如下(。只会对结构进行插入和编辑操作,而不会擦除。
但是,由于写入操作将比读取操作频繁得多(大约 ~1m 写入操作与同一时间段内的 15-20,000 次读取操作(,我担心使用唯一锁会影响读取操作的性能。
我想知道是否有更好/更简单的方法来为我的问题实现简单的并发映射?例如,每次执行写入/读取操作时,只锁定结构本身而不是整个映射会更好吗?
我已经研究了英特尔TBB并发无序列图和潘兴的Junction图,但如果可能的话,我宁愿坚持只使用STL。
我正在使用 C++11,因此shared_lock不可用。我考虑使用 boost::shared_lock 进行读取操作,但我从这篇文章中了解到,锁定shared_mutex的成本高于普通成本。
编辑:在注释中编辑代码发布讨论。
#include <mutex>
struct Foo
{
double bar1 = 0;
long bar2 = 0;
};
typedef std::shared_ptr<Foo> FooPtr;
class FooMap
{
std::mutex mMutex;
std::unordered_map<long, FooPtr> mMap;
public:
FooPtr get(long const& key)
{
return mMap[key];
}
void set(long const& key, double a, long b)
{
std::unique_lock<std::mutex> lock(mMutex);
mMap[key]->bar1 = a;
mMap[key]->bar2 = b;
}
};
好吧,我放弃了...恐怕你的代码已经偏离了我的想法。这就是我真正建议的,你写到共享对象的新实例中来创建新的foo:
#include <mutex>
struct Foo
{
double bar1 = 0;
long bar2 = 0;
};
typedef std::shared_ptr<Foo> FooPtr;
typedef std::shared_ptr<const Foo> CFooPtr;
class FooMap
{
std::mutex mMutex;
std::unordered_map<long, FooPtr> mMap;
public:
CFooPtr get(long const& key)
{
auto found = mMap.find(key);
if (found == mMap.end())
{
return nullptr;
}
return found->second;
}
void set(long const& key, double a, long b)
{
FooPtr tmp = make_shared<Foo>({a,b});
{
std::unique_lock<std::mutex> lock(mMutex);
mMap[key].swap(tmp);
}
// previous entry contents are destroyed outside mutex
}
};
在这里,您可以找到仅使用 STL 的无锁哈希映射设计 https://shlomisteinberg.com/2015/09/28/designing-a-lock-free-wait-free-hash-map/
声称在繁重的写入方面比 TBB 更好。