C++ 在现代c+中,当getter需要将受保护的资源作为共享ptr返回时,如何设计单写多读+;?
我有一个writer线程在一个对象中写入一个映射,许多reader对象在各自的线程中在映射上执行只读,我当前的设计如下所示C++ 在现代c+中,当getter需要将受保护的资源作为共享ptr返回时,如何设计单写多读+;?,c++,concurrency,c++14,c++17,mutex,C++,Concurrency,C++14,C++17,Mutex,我有一个writer线程在一个对象中写入一个映射,许多reader对象在各自的线程中在映射上执行只读,我当前的设计如下所示 class MyClass { private: shared_ptr<map<int, int>> my_map; mutable shared_mutex mu; public: void update_or_add(pair<int, int> entry); shared_lock<share
class MyClass {
private:
shared_ptr<map<int, int>> my_map;
mutable shared_mutex mu;
public:
void update_or_add(pair<int, int> entry);
shared_lock<shared_mutex> get_read_lock();
shared_ptr<const map<int, int>> get_map();
}
void MyClass::update_or_add(pair<int, int> entry) {
lock_guard<shared_mutex> locker(mu);
// do update on my_map
}
shared_lock<shared_mutex> MyClass::get_read_lock() {
shared_lock<shared_mutex> locker(mu);
return locker;
shared_ptr<const map<int, int>> MyClass::get_map() {
return my_map;
}
class-MyClass{
私人:
共享我的地图;
可变共享_互斥mu;
公众:
无效更新或添加(配对条目);
共享锁定获取读取锁定();
共享_ptr get_map();
}
void MyClass::更新或添加(配对条目){
锁柜(mu);
//在我的地图上更新吗
}
共享锁定MyClass::get\u read\u lock(){
共享锁柜(mu);
返回储物柜;
共享的\u ptr MyClass::get\u map(){
返回我的地图;
}
下面是我可以如何使用它
//writer
//thread-1
MyClass obj;
while(true)
obj.update_or_add(entry);
//readers
//thread-2
shared_lock<shared_mutex> locker(obj.get_read_lock());
auto mymap = obj.get_map();
//some computation on mymap
....
//thread-n
shared_lock<shared_mutex> locker(obj.get_read_lock());
auto mymap = obj.get_map();
//some computation on mymap
//编写器
//线程-1
MyClass obj;
while(true)
对象更新或添加(条目);
//读者
//螺纹-2
共享锁柜(obj.get_read_lock());
auto mymap=obj.get_map();
//关于mymap的一些计算
....
//线程-n
共享锁柜(obj.get_read_lock());
auto mymap=obj.get_map();
//关于mymap的一些计算
关于上述问题,我有两个问题
谢谢。这里有一个非常简单的共享资源:
template<class T>
struct shared_threadsafe {
template<class F>
auto read(F&& f)const{
auto l = lock(); // shared lock
return f(t); // const access
}
template<class F>
auto write(F&& f){
auto l = lock(); // exclusive lock
return f(t); // non-const access
}
// construct from a T
explicit shared_threadsafe( T in ):t(std::forward<T>(in)){}
// default construct
shared_threadsafe()=default;
shared_threadsafe(shared_threadsafe const&)=delete; // it can be written, but don't
shared_threadsafe& operator=(shared_threadsafe const&)=delete; // it can be written, but don't
~shared_threadsafe()=default;
private:
mutable std::shared_mutex m;
T t;
auto lock() const { return std::shared_lock{m}; }
auto lock() { return std::unique_lock{m}; }
}
读卡器线程:
bob.write([&](auto& bob){ bob.insert( p ); });
bob.read([&](auto& bob){
// cos=de that reads from the map `bob`
});
如果读取器线程具有const
引用或指针,则它们仅具有读取权限
实际上,我会想出一些操作,让共享线程安全在某个类中是私有的,并且只公开这些操作
通常,公开完整的读/写锁表明您的代码级别还不够高。基于锁的并发无法组合,也无法很好地扩展。当您公开在锁中运行任意代码的能力时,您会鼓励组合,这是一场灾难
我的共享threadsafe是一个尝试性的折衷方案,因为锁代码至少编写了一次,并且基于范围。我隐藏它是因为它仍然没有编写
根据您的读/写操作以及延迟的成本,移动到争用副本版本也可能是明智的。在此计划下,读卡器将获得指向其具有完全常量访问权限的表的智能指针。写卡器以写方式复制(cow)如果存在争用,则执行快速更新。写入时拷贝结果仅对写入发生后出现的读者可见
手写(非std)映射可以进行部分cow更新,共享表中新旧读取之间保持不变的部分
但在这一点上,您开始考虑DB。无论如何,您应该从DB开始。“一些计算”-什么计算?一般来说,好的线程安全设计并不能构成。而公开读或写锁的API也不能扩展。
bob.read([&](auto& bob){
// cos=de that reads from the map `bob`
});