多备份数据更新管理器模板设计(C++ Template)

在网络服务等需要提供不间断服务的程序中,程序的运行时升级通常都是一项常规任务,例如:

    1)运行时修改一些参数配置;

    2)运行时修改一个算法模块(动态库);

为了在执行这些任务时,程序不停(仍使用旧配置或旧模块运行),常见的解决方案包括:

    1)增加冗余的配置项或模块句柄的存储空间(所有这些数据打包成一个结构体),程序运行时使用其中的一份;当需要更新时,在更新的过程中将新的配置(或模块句柄)内容存储至备用内存;加载完成后将运行时配置(或模块句柄)指针指向新的内存地址。由于修改配置(或模块句柄)的频率远小于这些内容的读取频率,因此一个线程执行更新操作即可。另外,即使外加有多个线程同时读取,由于只涉及到配置项(或模块句柄)的整体结构体的这一个指针修改,读线程读到的值无非是“旧指针”和“新指针”二者之一(如果内存读写模型不支持这一点,或者在这种情况下可能有第三种,甚至第四种情况出现,本方案将不可用),因此程序仍能正常执行,并最终使用更新后的内容运行。

    2)程序通过一个主进程协调,具体任务由工作进程完成。外界通知这个主进程使用新的配置(或模块),主进程便创建新的工作进程,这些新启动的进程自然会使用新的配置(或模块);当新创建的进程一切就绪之后,主进程便会通知其他进程结束,并在之后将新的任务委派给新创建的进程。Nginx的设计便是这种方案的一个典型。

 

这里设计的一个C++模板是上述解决方案1)的一种实现(完整地VS2008项目代码在这里):

//
// 数据清理函数指针类型
//
template<typename T>
struct DataCleaner {
    typedef void (*ClearFun)(T*);
};

template<typename T>
void _default_reset_fun_(T* t)
{
    memset(t, 0, sizeof(T));
};

//
// 多备份数据更新管理器
//
template<typename T, const size_t POOLSIZE=2, bool static_memory=true>
class LatestDataManager;

template<typename T, const size_t POOLSIZE>
class LatestDataManager<T, POOLSIZE, true>
{
public:
    typedef T value_type;

    LatestDataManager(){m_clf = _default_reset_fun_<T>;}
    ~LatestDataManager(){}

    T& GetCurrent(){ return m_elem[m_current]; }
    T& GetNext(){
        size_t next = (m_current+1)%POOLSIZE;
        m_clf(&m_elem[next]);
        return m_elem[next]; 
    }
    void UseLatest(){ m_current = (m_current+1)%POOLSIZE; }
    void SetClearFun(typename DataCleaner<T>::ClearFun f){ m_clf = f; }
private:
    T                           m_elem[POOLSIZE];
    size_t                      m_current;
    typename DataCleaner<T>::ClearFun    m_clf;
};

template<typename T, const size_t POOLSIZE>
class LatestDataManager<T, POOLSIZE, false>
{
public:
    typedef T value_type;

    LatestDataManager(){memset(m_elem, 0, POOLSIZE*sizeof(T*));}
    ~LatestDataManager(){}

    T* GetCurrent(){ return m_elem[m_current]; }
    T* GetNext(){
        size_t next = (m_current+1)%POOLSIZE;
        if(NULL!=m_elem[next]){
            delete m_elem[next];
            m_elem[next] = NULL;
        }
        m_elem[next] = new T;
        return m_elem[next]; 
    }
    void UseLatest(){ m_current = (m_current+1)%POOLSIZE; }
    void SetClearFun(typename DataCleaner<T>::ClearFun){}
private:
    T*                          m_elem[POOLSIZE];
    size_t                      m_current;
};


测试代码:

template<typename T>
void _primdata_reset_fun_(T* t)
{
    *t = 0;
}
typedef LatestDataManager<int, 2, true>  LatestConfig;

template<typename T>
void _container_reset_fun_(T* t)
{
    if(t) t->clear();
}
typedef LatestDataManager<std::vector<std::string>, 2, false>  LatestMachines;


{
    LatestConfig g_cfg;
    g_cfg.SetClearFun( _primdata_reset_fun_< LatestConfig::value_type > );
    {// 更新者 ... ...
        g_cfg.GetNext() = 3;
        g_cfg.UseLatest();
    }
    {// 使用者 ... ...
        int config = g_cfg.GetCurrent();
        std::cout << config << std::endl;
    }
}

{
    LatestMachines g_lm;
    g_lm.SetClearFun( _container_reset_fun_< LatestMachines::value_type > );
    {// 更新者 ... ...
        std::vector<std::string>* machines = g_lm.GetNext();
        machines->push_back("192.168.0.1");
        machines->push_back("192.168.0.2");
        machines->push_back("192.168.0.3");
        g_lm.UseLatest();
    }
    {// 使用者 ... ...
        std::vector<std::string>* machines = g_lm.GetCurrent();
        for(std::vector<std::string>::iterator it=machines->begin(); it!=machines->end(); ++it)
        {
            std::cout << it->c_str() << std::endl;
        }
    }
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值