RPCZ中的智能指針單例
(金慶的專欄)
智能指針單例應(yīng)用于 RPCZ 庫(kù)以實(shí)現(xiàn)庫(kù)的自動(dòng)初始化與自動(dòng)清理. 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, 回復(fù)者 David Rodríguez Ibeas 提出了優(yōu)化意見, 并被原作者認(rèn)同. 本作者提出進(jìn)一步優(yōu)化, 附于本文尾部. Singleton using boost weak_ptr and shared_ptr 應(yīng)用 boost weak_ptr 和 shared_ptr 實(shí)現(xiàn)單例 ------------------------------------------------------------------ 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. 需求: 初次使用時(shí)構(gòu)造單例(而非進(jìn)程開始時(shí)構(gòu)造), 并且在最后的客戶代碼使用完后就銷毀單例. 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. 注意: 因此有可能進(jìn)程的生命期內(nèi)會(huì)存在多個(gè)單例實(shí)例, 但是, 任一時(shí)刻最多只會(huì)有一個(gè)對(duì)象(析造完成后才允許新的構(gòu)造). 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. 簡(jiǎn)單方案的問題: 沒有對(duì)同時(shí)初始化, 或者同時(shí)刪除和構(gòu)造進(jìn)行保護(hù). Solution: The construction and destruction of the singleton instance(s) has to be protected additionally. 解決方案: 對(duì)單例的構(gòu)造和析構(gòu)額外添加保護(hù). (金慶: 原代碼中的 class atomic_bool 已替換為 boost::atomic_bool, 以簡(jiǎn)化代碼.)
dynamic_singleton.h
#pragma once #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> #include <boost/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> impl_t; impl_t pimpl; struct deleter; friend struct deleter; };
#include "dynamic_singleton.h" #include <boost/atomic.hpp> #include <boost/weak_ptr.hpp> #include <boost/thread/recursive_mutex.hpp> #include <boost/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<dynamic_singleton> 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); }
#include "dynamic_singleton.h" #include <iostream> #include <boost/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; }
* 用 condition 代替 sleep(). * 因?yàn)?condition 已有 mutex, 所以 the_object_exists 從 atomic_bool 改為 bool. * 不需要?jiǎng)?chuàng)建 dynamic_singleton::impl 實(shí)例, 所以其構(gòu)造析構(gòu)改為私有. * 把 the_object_exists = true; 從 finish_destruction() 移到 start_construction(), finish_destruction()成為空函數(shù)可刪除. // 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<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: 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_;
* get_instance()多數(shù)情況下不需要加鎖, 僅當(dāng)需要初始化時(shí)才加鎖 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() 內(nèi)聯(lián) * 分離單件相關(guān)代碼到獨(dú)立的頭文件與實(shí)現(xiàn)文件 (impl改名為helper) dynamic_singleton.h
#pragma once #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> class dynamic_singleton : private boost::noncopyable { public: typedef boost::shared_ptr<dynamic_singleton> 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(); }
#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); }
#pragma once #include <boost/noncopyable.hpp> #include <boost/thread.hpp> #include <boost/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(); }
#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; }
Powered by: C++博客 Copyright © 金慶