Creative Commons License
本Blog采用 知识共享署名-非商业性使用-禁止演绎 3.0 Unported许可协议 进行许可。 —— Fox <游戏人生>

游戏人生

游戏人生 != ( 人生 == 游戏 )
站点迁移至:http://www.yulefox.com。请订阅本博的朋友将RSS修改为http://feeds.feedburner.com/yulefox
posts - 62, comments - 508, trackbacks - 0, articles - 7

ACE vs Boost: Singleton的实现

Posted on 2009-09-22 00:38 Fox 阅读(7220) 评论(9)  编辑 收藏 引用 所属分类: T技术碎语

本文同步自游戏人生

以前曾经讨论过Singleton的实现,这次在对照ACE和Boost代码的时候,又重新审视了一下二者对Singleton不同的实现。其间的差别也体现了不同的编程哲学:ACE的实现更加偏重多线程中的安全和效率问题;Boost的实现则偏重于使用语言自身的特性满足Singleton模式的基本需求。

o ACE的实现

Douglas C. Schmidt在Double-Checked Locking: An Optimization Pattern for Efficiently Initializing and Accessing Thread-safe Objects一文中对double-check lock(一般译为双检锁)进行了详细的阐述。

ACE的Singleton使用Adapter模式实现对其他类的适配,使之具有全局唯一的实例。由于C++标准并非明确指定全局静态对象的初始化顺序,ACE使用double-check lock保证线程安全,并使之不受全局静态对象初始化顺序的影响,同时也避免了全局静态实现方式的初始化后不使用的开销。

如果你能够准确的区分以下三种实现的弊端和隐患,对double-check lock也就有了足够的了解。

// -------------------------------------------
class Singleton
{
public:
    static Singleton *instance (void)
    {
        // Constructor of guard acquires
        // lock_ automatically.
        Guard<Mutex> guard (lock_);
        // Only one thread in the
        // critical section at a time.
        if (instance_ == 0)
            instance_ = new Singleton;
        return instance_;
        // Destructor of guard releases
        // lock_ automatically.
    }
private:
    static Mutex lock_;
    static Singleton *instance_;
};

// ---------------------------------------------
static Singleton *instance (void)
{
    if (instance_ == 0) {
        Guard<Mutex> guard (lock_);
        // Only come here if instance_
        // hasn’t been initialized yet.
        instance_ = new Singleton;
    }
    return instance_;
}

// ---------------------------------------------
class Singleton
{
public:
    static Singleton *instance (void)
    {
        // First check
        if (instance_ == 0)
        {
            // Ensure serialization (guard
            // constructor acquires lock_).
            Guard<Mutex> guard (lock_);
            // Double check.
            if (instance_ == 0)
                instance_ = new Singleton;
        }
        return instance_;
        // guard destructor releases lock_.
    }
private:
    static Mutex lock_;
    static Singleton *instance_;
};

更多详情,见Schmidt老师的原文和ACE_Singleton实现。

o Boost的实现

Boost的Singleton也是线程安全的,而且没有使用锁机制。当然,Boost的Singleton有以下限制(遵从这些限制,可以提高效率):

o The classes below support usage of singletons, including use in program startup/shutdown code, AS LONG AS there is only one thread running before main() begins, and only one thread running after main() exits.

o This class is also limited in that it can only provide singleton usage for classes with default constructors.

// T must be: no-throw default constructible and no-throw destructible
template <typename T>
struct singleton_default
{
private:
    struct object_creator
    {
        // This constructor does nothing more than ensure that instance()
        //  is called before main() begins, thus creating the static
        //  T object before multithreading race issues can come up.
        object_creator() { singleton_default<T>::instance(); }
        inline void do_nothing() const { }
    };
    static object_creator create_object;

    singleton_default();

public:
    typedef T object_type;

    // If, at any point (in user code), singleton_default<T>::instance()
    //  is called, then the following function is instantiated.
    static object_type & instance()
    {
        // This is the object that we return a reference to.
        // It is guaranteed to be created before main() begins because of
        //  the next line.
      static object_type obj;

      // The following line does nothing else than force the instantiation
      //  of singleton_default<T>::create_object, whose constructor is
      //  called before main() begins.
      create_object.do_nothing();

      return obj;
    }
};
template <typename T>
typename singleton_default<T>::object_creator
singleton_default<T>::create_object;

对于多数Singleton使用,Boost提供的版本完全能够满足需求。为了效率,我们有必要对其使用作出一定的限制。

而在多线程编程中,则有必要使用double-check lock降低频繁加锁带来的开销。

-------------------------------------------------------------------------------

PS: 欣赏Soft的一句话:经得起诱惑,耐得住寂寞

Feedback

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-22 02:44 by OwnWaterloo
boost够机灵的, 避重就轻。


singleton可能会遇到的问题, 以及如何解决, 最详尽的资料在《modern c++ design》中有介绍。 问题大致有如下几个方面:
1. 限制实例数量
2. singleton相互引用
3. dead-reference
4. 线程安全


C++中:
singleton这种模式能"直接"解决的问题只有1;利用C++语言机制 —— private —— 来限制实例数量。
而问题1也是众多文章讨论得最多的, 简单嘛……

解决1问题,并不一定需要singlet这种模式;而其他问题又不是singleton这种"模式"本身能解决的。
综上, singleton in cplusplus is bullshit ……



boost这种实现,只能解决1, 在一定条件下,能解决4。
如果遇见2、3, 同样完蛋。

boost.singleton解决4,需要满足如下条件:
"The classes below support usage of singletons, including use in program startup/shutdown code, AS LONG AS there is only one thread running before main() begins, and only one thread running after main() exits."
如果这种条件能被满足, 直接使用全局变量同样是线程安全的。

如果真的需要解决问题1,以及难看的全局变量:
可以将这个全局变量以及类的定义放在单一翻译单元中,并在该翻译但与实现若干wrapper函数即可。

同样, 对于问题2和3, 全局变量也通常会坏事。

综上, boost.singleton, 简直就是为模式而模式。

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-22 11:07 by 陈梓瀚(vczh)
@OwnWaterloo
一个程序应该满足下面的条件:
将程序里面所有的全局变量、函数和类的暴露对象排序(只需存在一种排序即可),对于所有的0<=n<=这些东西的数量,删除前n个,程序应当可以编译。

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-22 14:29 by OwnWaterloo
@陈梓瀚(vczh)
没明白。 这个条件能保证什么? 编译时的依赖关系?

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-22 17:32 by 陈梓瀚(vczh)
@OwnWaterloo
便于你的代码以后复用,久而久之组织成类库。

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-22 17:44 by OwnWaterloo
@陈梓瀚(vczh)
这跟singleton有什么关系?

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-24 17:45 by 凡客诚品
便于你的代码以后复用,久而久之组织成类库

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-28 21:59 by adah
在double-checked locking pattern已经被批驳了这么久之后还写这样的文章,作者也可真称得上孤陋寡闻了。

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-09-29 09:19 by Fox
@adah
给个链接我了解一下DCL被批的原因吧,我承认孤陋寡闻了。

# re: ACE vs Boost: Singleton的实现  回复  更多评论   

2009-12-03 16:06 by 金庆
以上DCL单件的实现可能是有缺陷。但我不是很确信。因为ACE确实是这样实现的。按我的理解,加个volatile就好了。“The "Double-Checked Locking is Broken" Declaration”( http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html )一文可作参考。不知adah所说的批驳是否指这一点?

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理