(Ab)使用shared_ptr作为引用计数器
最近我想到了一个狡猾的计划(tm :P)) 我必须更新程序中的设置结构(假设每 15 秒更新一次)。设置结构由多个函数使用,并且每个函数都由多个线程调用。 所以我需要一个引用计数器来知道何时可以安全地释放旧的设置结构。 那么这是正确的方法吗? 如果你没有仔细阅读代码,请不要回应没关系,当涉及到共享指针时,这样的滥用很容易出错(相信我)。 编辑:我忘了提到重要的部分。我认为这个实现可以防止引用计数器下降到 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();
}
}
Recently i thought of a cunning plan(tm :P))
I have to update settings structure in my program(lets say every 15 seconds). Settings structure is used by multiple functions and every of those functions is called by multiple threads.
So I need a reference counter to know when it is safe to free the old settings struct.
So is this the correct way to do it?
Please don't respond that it is OK if you haven't read the code carefully, when it comes to shared pointers it's easy to make mistakes when doing abuses like this(trust me).
EDIT:I forgott to mention important part. I think that this implementation prevents the ref counter dropping to 0, because I initialize it in updateSettings() and it doesn't drop until it is called again(and then myFucntion uses the other of the 2 settings in the memory).
#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
}
}
EDIT:using feedback from the comments I updated the code:
#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();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不会相信这段代码。我相信除了两个引用计数之外,不同线程共享的所有内存都缺乏适当的内存屏障。
对我来说,这看起来是一个很好的 shared_mutex 应用程序。
编辑:
20.7.2.2 [util.smartptr.shared]/p4 说:
然而,除了使用shared_mutex,另一种选择可能是使用20.7.2.5shared_ptr原子访问中的API[util.smartptr.shared.atomic]:
shared_mutex 会更容易得到正确的结果。但原子的shared_ptr API可能会产生更高性能的解决方案。
更新:
这是shared_mutex解决方案未经测试的代码(注意shared_mutex不是std,而是第3方库):
这是未经测试的代码,它使用shared_ptr的原子加载/存储函数:
I would not trust this code. I believe it is lacking proper memory barriers on all memory shared by the different threads, except for the two reference counts.
This looks like a good application for shared_mutex to me.
Edit:
20.7.2.2 [util.smartptr.shared]/p4 says:
However, instead of using a shared_mutex, another option might be to use the API in 20.7.2.5 shared_ptr atomic access [util.smartptr.shared.atomic]:
shared_mutex will be easier to get right. But the atomic shared_ptr API may yield a higher performance solution.
Update:
Here is untested code for the shared_mutex solution (note shared_mutex is not std, but is 3rd party library):
Here is untested code which uses the atomic load/store functions for shared_ptr: