IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    RPCZ中的智能指针单例

    金庆发表于 2015-02-28 13:33:00
    love 0

    RPCZ中的智能指针单例


    (金庆的专栏)


    智能指针单例应用于 RPCZ 库以实现库的自动初始化与自动清理.
    RPCZ: RPC implementation for Protocol Buffers over ZeroMQ
    https://github.com/jinq0123/rpcz

    代码来自: (A dynamic) Singleton using weak_ptr and shared_ptr
    http://boost.2283326.n4.nabble.com/A-dynamic-Singleton-using-weak-ptr-and-shared-ptr-td2581447.html

    以下为该文摘译与代码整理.
    原作者 Martin Ba,
    回复者 David Rodríguez Ibeas 提出了优化意见, 并被原作者认同.
    本作者提出进一步优化, 附于本文尾部.

    Singleton using boost weak_ptr and shared_ptr
    应用 boost weak_ptr 和 shared_ptr 实现单例
    ------------------------------------------------------------------
    by Martin Ba

    Requirement: Singleton that is constructed on first use (not on process
    start) and destroyed after the last "client-code" has finished with it.

    需求: 初次使用时构造单例(而非进程开始时构造),
    并且在最后的客户代码使用完后就销毁单例.

    Note: It is therefore possible that more that one Singleton instances
    exist within a process's lifetime, BUT there must only be at most one
    Object active at any given time (Construction must not run before
    destruction has finished.

    注意: 因此有可能进程的生命期内会存在多个单例实例, 但是,
    任一时刻最多只会有一个对象(析造完成后才允许新的构造).

    Starting point: http://lists.boost.org/boost-users/2002/10/2014.php

    Problem of the simple solution: No protection against multiple
    initialization and against simultaneous deletion and construction.

    简单方案的问题: 没有对同时初始化, 或者同时删除和构造进行保护.

    Solution: The construction and destruction of the singleton instance(s)
    has to be protected additionally.

    解决方案: 对单例的构造和析构额外添加保护.

    (金庆: 原代码中的 class atomic_bool 已替换为 boost::atomic_bool, 以简化代码.)

    dynamic_singleton.h

    #pragma once
    #include noncopyable.hpp>
    #include <boostshared_ptr.hpp>
    #include scoped_ptr.hpp>
    class dynamic_singleton : private boost::noncopyable
    {
    public:
        typedef boost::shared_ptr<dynamic_singleton> shared_t;
        static shared_t get_instance();
        / Interface:
        void example(int cookie);
        // ...
    private:
        dynamic_singleton();
        virtual ~dynamic_singleton();
        struct impl;
        typedef boost::scoped_ptr impl_t;
        impl_t pimpl;
        struct deleter;
        friend struct deleter;
    };
    

    dynamic_singleton.cpp

    #include "dynamic_singleton.h"
    #include atomic.hpp>
    #include <boostweak_ptr.hpp>
    #include threadrecursive_mutex.hpp>
    #include thread.hpp>
    #define MESG(msg)   \
        printf("%s\n", msg); \
        **/
    struct dynamic_singleton::impl : private boost::noncopyable
    {
        impl()  {}
        ~impl() {}
        static void start_construction()
        {
            boost::xtime spin_time;
            spin_time.sec = 1;
            while(the_object_exists) {
                boost::thread::sleep(spin_time);
            }
        }
        static void finish_construction()
        {
            assert(!the_object_exists);
            the_object_exists = true;
        }
        static void finish_destruction()
        {
            assert(the_object_exists);
            the_object_exists = false;
        }
        typedef boost::weak_ptr internal_shared_t;
        static internal_shared_t the_object;
        static boost::recursive_mutex sync_init;
        static boost::atomic_bool the_object_exists;
    };
    dynamic_singleton::impl::internal_shared_t
        dynamic_singleton::impl::the_object;
    boost::recursive_mutex
        dynamic_singleton::impl::sync_init;
    boost::atomic_bool
        dynamic_singleton::impl::the_object_exists;
    struct dynamic_singleton::deleter
    {
        void operator() (dynamic_singleton* p)
        {
            assert(p);
            delete p;
            impl::finish_destruction();
        }
    };
    dynamic_singleton::shared_t dynamic_singleton::get_instance()
    {
        // Syncronise Initialization:
        boost::recursive_mutex::scoped_lock lock(impl::sync_init);
        MESG(__FUNCTION__);
        // Acquire singleton pointer:
        shared_t object_ptr = impl::the_object.lock();
        if(!object_ptr.use_count()) {
            impl::start_construction();
            object_ptr.reset(new dynamic_singleton(), dynamic_singleton::deleter());
            impl::the_object = object_ptr;
            impl::finish_construction();
        }
        return object_ptr;
    }
    dynamic_singleton::dynamic_singleton()
    {
        pimpl.reset(new impl());
        MESG(__FUNCTION__);
        // For example open a unique system or process global resource
        printf(" >> Singleton opens the global resouce.\n");
    }
    dynamic_singleton::~dynamic_singleton()
    {
        MESG(__FUNCTION__);
        // For example close a unique system or process global resource
        printf(" << Singleton closes the global resouce.\n");
    }
    void dynamic_singleton::example(int cookie)
    {
        printf("%s(%d)\n", __FUNCTION__, cookie);
    }
    

    main.cpp

    #include "dynamic_singleton.h"
    #include 
    #include thread.hpp>
    struct singleton_user
    {
        explicit singleton_user(int num)
            : num_(num)
        { }
        void operator()()
        {
            using namespace std;
            printf("%d uses singleton ...\n", num_);
            dynamic_singleton::shared_t s = dynamic_singleton::get_instance();
            s->example(num_);
        }
        int num_;
    };
    int main(int argc, char* argv[])
    {
        boost::thread t1( singleton_user(1) );
        boost::thread t2( singleton_user(2) );
        boost::thread t3( singleton_user(3) );
        boost::thread t4( singleton_user(4) );
        boost::thread t5( singleton_user(5) );
        t1.join();
        t2.join();
        t3.join();
        t4.join();
        t5.join();
        return 0;
    }
    <pre>
        

    David Rodríguez Ibeas 提出建议:

    * 用 condition 代替 sleep().
    * 因为 condition 已有 mutex, 所以 the_object_exists 从 atomic_bool 改为 bool.
    * 不需要创建 dynamic_singleton::impl 实例, 所以其构造析构改为私有.
    * 把 the_object_exists = true; 从 finish_destruction() 移到 start_construction(),
    finish_destruction()成为空函数可删除.

    // Using boost::condition:
    struct dynamic_singleton::impl : private boost::noncopyable
    {
    static void start_construction()
    {
    boost::recursive_mutex::scoped_lock lock( sync_ );
    while ( the_object_exists ) {
    cond_.wait( lock );
    }
    the_object_exists = true;
    }
    static void finish_destruction()
    {
    boost::recursive_mutex::scoped_lock lock( sync_ );
    the_object_exists = false;
    cond_.notify_one();
    }
    typedef boost::weak_ptr internal_shared_t;
    static internal_shared_t the_object;

    static boost::recursive_mutex sync_init;
    static boost::recursive_mutex sync_; // moved from atomic_bool
    static bool the_object_exists; // plain bool, synch'ed with sync_
    static boost::condition_variable_any cond_;

    private:
    impl() {}
    ~impl() {}
    };

    dynamic_singleton::impl::internal_shared_t dynamic_singleton::impl::the_object;
    boost::recursive_mutex dynamic_singleton::impl::sync_init;
    boost::recursive_mutex dynamic_singleton::impl::sync_;
    bool dynamic_singleton::impl::the_object_exists = false;
    boost::condition_variable_any dynamic_singleton::impl::cond_;

    RPCZ 中的进一步优化:

    * get_instance()多数情况下不需要加锁, 仅当需要初始化时才加锁

    dynamic_singleton::shared_t dynamic_singleton::impl::get_instance()
    {
    shared_t object_ptr = impl::the_object.lock();
    if (object_ptr) return object_ptr;

    // Syncronise Initialization:
    boost::recursive_mutex::scoped_lock lock(impl::sync_init);
    ...
    }

    * get_instance() 内联
    * 分离单件相关代码到独立的头文件与实现文件
    (impl改名为helper)

    dynamic_singleton.h

    #pragma once
    #include noncopyable.hpp>
    #include <boostshared_ptr.hpp>
    class dynamic_singleton : private boost::noncopyable
    {
    public:
        typedef boost::shared_ptr shared_t;
        inline static shared_t get_instance();
        // Interface:
        void example(int cookie);
        // ...
    private:
        dynamic_singleton();
        virtual ~dynamic_singleton();
        struct helper;
        struct deleter;
        friend struct deleter;
    };
    #include "dynamic_singleton_helper.h"
    inline dynamic_singleton::shared_t dynamic_singleton::get_instance()
    {
        return helper::get_instance();
    }
    

    dynamic_singleton.cpp

    #include "dynamic_singleton.h"
    #define MESG(msg)   \
        printf("%s\n", msg); \
        /**/
    dynamic_singleton::dynamic_singleton()
    {
        MESG(__FUNCTION__);
        // For example open a unique system or process global resource
        printf(" >> Singleton opens the global resouce.\n");
    }
    dynamic_singleton::~dynamic_singleton()
    {
        MESG(__FUNCTION__);
        // For example close a unique system or process global resource
        printf(" << Singleton closes the global resouce.\n");
    }
    void dynamic_singleton::example(int cookie)
    {
        printf("%s(%d)\n", __FUNCTION__, cookie);
    }
    

    dynamic_singleton_helper.h

    #pragma once
    #include noncopyable.hpp>
    #include <boostthread.hpp>
    #include weak_ptr.hpp>
    struct dynamic_singleton::helper : private boost::noncopyable
    {
        static inline dynamic_singleton::shared_t get_instance();
        static void start_construction();
        static void finish_destruction();
        typedef boost::weak_ptr<dynamic_singleton> internal_shared_t;
        static internal_shared_t the_object;
        static boost::recursive_mutex sync_init;
        static boost::recursive_mutex sync_;    / moved from atomic_bool
        static bool the_object_exists;  // plain bool, synch'ed with sync_
        static boost::condition_variable_any cond_;
    private:
        helper() {}
        ~helper() {}
    private:
        static dynamic_singleton::shared_t make_instance();
    };
    inline dynamic_singleton::shared_t dynamic_singleton::helper::get_instance()
    {
        shared_t object_ptr = the_object.lock();
        if (object_ptr) return object_ptr;
        return make_instance();
    }
    

    dynamic_singleton_helper.cpp

    #include "dynamic_singleton.h"
    void dynamic_singleton::helper::start_construction()
    {  
        boost::recursive_mutex::scoped_lock lock( sync_ );
        while ( the_object_exists ) {
            cond_.wait( lock );
        }
        the_object_exists = true;
    }
    void dynamic_singleton::helper::finish_destruction()
    {  
        boost::recursive_mutex::scoped_lock lock( sync_ );
        the_object_exists = false;
        cond_.notify_one();
    }
    dynamic_singleton::helper::internal_shared_t dynamic_singleton::helper::the_object;
    boost::recursive_mutex dynamic_singleton::helper::sync_init;
    boost::recursive_mutex dynamic_singleton::helper::sync_;
    bool dynamic_singleton::helper::the_object_exists = false;
    boost::condition_variable_any dynamic_singleton::helper::cond_;
    struct dynamic_singleton::deleter
    {
        void operator() (dynamic_singleton* p)
        {
            assert(p);
            delete p;
            helper::finish_destruction();
        }
    };
    dynamic_singleton::shared_t dynamic_singleton::helper::make_instance()
    {
        // Syncronise Initialization:
        boost::recursive_mutex::scoped_lock lock(sync_init);
        // Acquire singleton pointer:
        shared_t object_ptr = the_object.lock();
        if (object_ptr) return object_ptr;
        start_construction();
        object_ptr.reset(new dynamic_singleton(), dynamic_singleton::deleter());
        the_object = object_ptr;
        return object_ptr;
    }
    
    代码打包下载:
    /Files/jinq0123/dynamic_singleton_src.zip



    金庆 2015-02-28 21:33 发表评论


沪ICP备19023445号-2号
友情链接