最近我想到了一个狡猾的计划(tm:P)) 我必须更新程序中的设置结构(假设每15秒一次)。设置结构由多个函数使用,并且每个函数都由多个线程调用。 所以我需要一个引用计数器来知道何时释放旧的设置结构是安全的。 那么这是正确的方法吗? 如果你没有仔细阅读代码,请不要回答它是正常的,当涉及共享指针时,在做这样的滥用时很容易出错(相信我)。 编辑:我原谅提到重要的部分。我认为这个实现可以防止ref计数器降到0,因为我在updateSettings()中初始化它并且在它再次被调用之前它不会丢弃(然后myFucntion使用内存中的2个设置中的另一个)。
#include<memory>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
struct STNGS
{
int i;
vector<double> v;
};
static int CUR_STNG=0;
shared_ptr<STNGS> stngsArray[2];
int myFunction() //called by multiple threads
{
shared_ptr<STNGS> pStngs=stngsArray[CUR_STNG];
STNGS& stngs=*pStngs;
//do some stuff using stngs
}
void updateSettings()
{
auto newIndex=(CUR_STNG+1)%2;
stngsArray[newIndex].reset(new STNGS);
CUR_STNG=newIndex;
}
void initialize()
{
auto newIndex=CUR_STNG;
stngsArray[newIndex].reset(new STNGS);
CUR_STNG=newIndex;
}
int main()
{
initialize();
//launch bunch of threads that are calling myFunction
while(true)
{
//call updateSettings every 15 seconds
}
}
编辑:使用评论中的反馈我更新了代码:
#include<memory>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
static const int N_STNG_SP=4;
static int CUR_STNG=0;
struct STNGS
{
int i;
vector<double> v;
STNGS()
{
for (int i=0;i<10;++i)
v.push_back(42);
}
};
shared_ptr<STNGS> stngs[N_STNG_SP];
int myFunction() //called by multiple threads
{
shared_ptr<STNGS> pStngs=stngs[CUR_STNG];
STNGS& stngs=*pStngs;
//do some stuff using stngs
}
void updateSettings()
{
auto pStng=new STNGS;
//fill *pStng
int newVer=(CUR_STNG+1)%N_STNG_SP;
stngs[newVer].reset(pStng);
CUR_STNG=newVer;
}
void initialize()
{
auto pStng=new STNGS;
//fill *pStng
int newVer=(CUR_STNG+1)%N_STNG_SP;
stngs[newVer].reset(pStng);
CUR_STNG=newVer;
}
int main()
{
initialize();
//launch bunch of threads that are calling myFunction
while(true)
{
//call updateSettings every 15 seconds
updateSettings();
}
}
答案 0 :(得分:2)
我不相信这段代码。我相信在不同线程共享的所有内存上缺少适当的内存屏障,除了两个引用计数。
这对shared_mutex来说似乎是一个很好的应用程序。
修改强>
20.7.2.2 [util.smartptr.shared] / p4说:
为了确定 成员的数据竞赛的存在 功能只能访问和修改 shared_ptr和weak_ptr对象 他们自己而不是他们提到的对象 到。
但是,不是使用shared_mutex,另一个选项可能是在20.7.2.5 shared_ptr atomic access [util.smartptr.shared.atomic]中使用API:
并发访问shared_ptr 来自多个线程的对象不会 如果访问是引入数据竞争 完全通过函数完成 本节和实例是 作为他们的第一个论点传递。
template<class T>
bool atomic_is_lock_free(const shared_ptr<T>* p);
template<class T>
shared_ptr<T> atomic_load(const shared_ptr<T>* p);
template<class T>
shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* p, memory_order mo);
template<class T>
void atomic_store(shared_ptr<T>* p, shared_ptr<T> r);
template<class T>
void atomic_store_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
template<class T>
shared_ptr<T> atomic_exchange(shared_ptr<T>* p, shared_ptr<T> r);
template<class T>
shared_ptr<T>
atomic_exchange_explicit(shared_ptr<T>* p, shared_ptr<T> r, memory_order mo);
template<class T>
bool
atomic_compare_exchange_weak(shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
template<class T>
bool
atomic_compare_exchange_strong( shared_ptr<T>* p, shared_ptr<T>* v, shared_ptr<T> w);
template<class T>
bool
atomic_compare_exchange_weak_explicit(shared_ptr<T>* p, shared_ptr<T>* v,
shared_ptr<T> w, memory_order success,
memory_order failure);
template<class T>
bool
atomic_compare_exchange_strong_explicit(shared_ptr<T>* p, shared_ptr<T>* v,
shared_ptr<T> w, memory_order success,
memory_order failure);
shared_mutex将更容易正确。但原子shared_ptr API可能会产生更高性能的解决方案。
<强>更新强>
这是shared_mutex解决方案的未经测试的代码(注意shared_mutex不是std,而是第三方库):
struct STNGS
{
int i;
vector<double> v;
ting::shared_mutex m;
};
STNGS stngs;
int myFunction() //called by multiple threads
{
shared_lock<shared_mutex> _(stngs.m);
//do some stuff using stngs
return 0;
}
void updateSettings()
{
unique_lock<shared_mutex> _(stngs.m);
//fill stngs
}
void initialize()
{
//fill stngs
}
这是未经测试的代码,它使用shared_ptr的原子加载/存储函数:
struct STNGS
{
int i;
vector<double> v;
};
shared_ptr<STNGS> pStng;
int myFunction() //called by multiple threads
{
shared_ptr<STNGS> stngs = atomic_load(&pStng);
//do some stuff using *stngs
return 0;
}
void updateSettings()
{
shared_ptr<STNGS> newStng(new STNGS);
//fill *newStng
atomic_store(&pStng, newStng);
}
void initialize()
{
pStng.reset(new STNGS);
//fill *pStng
}