C++11 (Ab)使用共享的ptr作为参考计数器

C++11 (Ab)使用共享的ptr作为参考计数器,c++11,shared-ptr,refcounting,C++11,Shared Ptr,Refcounting,最近我想到了一个狡猾的计划(tm:p)) 我必须在我的程序中更新设置结构(假设每15秒一次)。设置结构由多个函数使用,其中每个函数都由多个线程调用。 所以我需要一个引用计数器来知道何时可以安全地释放旧的设置结构。 那么这是正确的方法吗? 如果您没有仔细阅读代码,请不要回答这是可以的,当涉及到共享指针时,在这样滥用时很容易出错(相信我)。 编辑:我不提重要的部分。我认为这个实现可以防止ref计数器下降到0,因为我在updateSettings()中初始化了它,直到再次调用它时它才会下降(然后myf

最近我想到了一个狡猾的计划(tm:p)) 我必须在我的程序中更新设置结构(假设每15秒一次)。设置结构由多个函数使用,其中每个函数都由多个线程调用。 所以我需要一个引用计数器来知道何时可以安全地释放旧的设置结构。 那么这是正确的方法吗? 如果您没有仔细阅读代码,请不要回答这是可以的,当涉及到共享指针时,在这样滥用时很容易出错(相信我)。 编辑:我不提重要的部分。我认为这个实现可以防止ref计数器下降到0,因为我在updateSettings()中初始化了它,直到再次调用它时它才会下降(然后myfuntion使用内存中2个设置中的另一个)

#包括
#包括
#包括
#包括
使用名称空间std;
结构STNGS
{
int i;
向量v;
};
静态整数电流=0;
共享的ptr stngsArray[2];
int myFunction()//由多个线程调用
{
共享\ptr pStngs=stngsArray[CUR\u STNG];
STNGS&STNGS=*pStngs;
//使用stng做一些事情
}
void updateSettings()
{
自动新建索引=(当前值+1)%2;
stngsArray[newIndex].reset(新stng);
CUR_STNG=新索引;
}
void initialize()
{
自动更新索引=当前;
stngsArray[newIndex].reset(新stng);
CUR_STNG=新索引;
}
int main()
{
初始化();
//启动一组调用myFunction的线程
while(true)
{
//每15秒调用一次更新设置
}
}
编辑:使用来自评论的反馈,我更新了代码:

#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();
    }
}
#包括
#包括
#包括
#包括
使用名称空间std;
静态常数int N_STNG_SP=4;
静态整数电流=0;
结构STNGS
{
int i;
向量v;
STNGS()
{

对于(inti=0;i我不相信这段代码。我相信除了两个引用计数外,不同线程共享的所有内存上都缺少适当的内存屏障

对我来说,这似乎是一个很好的应用程序

编辑:

20.7.2.2[util.smartptr.shared]/p4表示:

为了确定 存在数据竞争、成员 功能只能访问和修改 共享的\u ptr和弱\u ptr对象 它们自己,而不是它们所指的对象 对

但是,另一个选项可能是使用20.7.2.5 shared_ptr atomic access[util.smartptr.shared.atomic]中的API,而不是使用共享的_互斥体:

对共享ptr的并发访问 来自多个线程的对象不存在 如果访问被拒绝,则引入数据竞争 仅通过中的函数完成 此部分和实例如下所示 作为他们的第一个论点通过

模板
布尔原子是无锁的(常数共享的);
模板
共享\u ptr原子负载(常数共享\u ptr*p);
模板
共享\u ptr原子\u加载\u显式(常量共享\u ptr*p,内存\u顺序mo);
模板
无效原子存储(共享存储*p,共享存储);
模板
无效原子存储显式(共享内存顺序mo);
模板
共享\u ptr原子\u交换(共享\u ptr*p,共享\u ptr);
模板
共享ptr
原子交换显式(共享ptr*p、共享ptr、内存顺序mo);
模板
布尔
原子比较交换弱(共享p、共享v、共享w);
模板
布尔
原子比较交换强(共享p、共享v、共享w);
模板
布尔
原子比较交换弱显式(共享ptr*p,共享ptr*v,
共享ptr w,内存顺序成功,
存储器(U顺序故障);
模板
布尔
原子比较交换强显式(共享ptr*p,共享ptr*v,
共享ptr w,内存顺序成功,
存储器(U顺序故障);
共享互斥将更容易得到正确的结果。但是原子共享的ptr API可能会产生更高性能的解决方案

更新:

以下是共享互斥体解决方案的未测试代码(注意,共享互斥体不是std,而是第三方库):

struct STNGS
{
int i;
向量v;
ting::shared_mutex m;
};
STNGS-STNGS;
int myFunction()//由多个线程调用
{
共享锁(stngs.m);
//使用stng做一些事情
返回0;
}
void updateSettings()
{
唯一锁(stngs.m);
//填充STNG
}
void initialize()
{
//填充STNG
}
以下是未经测试的代码,它使用原子加载/存储函数来实现共享\u 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
}
struct STNGS
{
int i;
向量v;
};
共享ptr pStng;
int myFunction()//由多个线程调用
{
共享的ptr STNG=原子负载(&pStng);
//使用*stng做一些事情
返回0;
}
void updateSettings()
{
共享新闻(新STNG);
//填充*新闻
原子商店(pStng、newStng);
}
void initialize()
{
pStng.重置(新STNG);
//填充*pStng
}

哦,另一个答案已经不存在了……但我想再问一次。你为什么需要原子存储?我知道需要原子存储,但原子存储不保证原子存储吗?我的意思是,变量没有锁定吗?就像我说的,其他函数只读取设置。如果是愚蠢的Q,请给我一些链接。说到愚蠢的Q:我现在明白了如果将原始指针用作构造函数的参数,则共享ptr不会复制该值。对我来说,它是新的(:P),因此我仍然不知道根据标准这是否是一个好主意。将原子指令视为围绕指定操作的互斥体(这实际上是boost实现的方式)。每个共享\u ptr都包含两个指针,除了更新引用计数外,还必须一致地读/写。如果设置共享\u ptr的线程在读卡器读取相同的共享\u 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);
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
}
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
}