您的位置:首页 > 其它

RPCZ中的智能指针单例

2015-03-02 21:01 246 查看
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 <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;
};

dynamic_singleton.cpp

#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);
}

main.cpp

#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;
}


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<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_;

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 <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();
}

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 <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();
}

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;
}


代码打包下载:

http://download.csdn.net/detail/jq0123/8467399
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: