首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

singleton与多线程解决思路

2012-02-23 
singleton与多线程 classsingleton{public:singleton&instance(){staticsingletonobjectreturnobject}}

singleton与多线程

class   singleton
{
public:
        singleton&   instance()
        {
                      static   singleton   object;
                      return   object;
          }
};

class   singleton
{
public:
        singleton&   instance()
        {
                      static   singleton*   refer;
                      if(refer   !=   0)
                      {
                              guard_lock(mutex);   //pseudo   code
                              if(refer   ==   0)
                              {
                                        static   singleton   object;
                                        refer   =   &object;
                                        return   object;
                                }
                      }
                      return   *refer;
          }
};

两个instance.我似乎发现应该用第二个,第一个从反汇编了来看,好像不是thread-safe的.大家来说说

[解决办法]
第一个,假如两个线程同时调用这个的话,有可能会调用两次构造函数.
< <C++ 设计新思维> > 中有讲的很详细,需要用线程锁来保护,
[解决办法]
那么,我问个问题:
当线程退出的时候,这个对象会析构吗?
[解决办法]
楼上说的不对。第一个就完全可以了,你定义的是静态变量,在主函数离开之后才会被CRT析构。不存在Thread Safety问题(指Instance()函数本身,如果有定义其他函数得具体分析)。不相信的话你可以在Destructor里面设个断点就知道了。

第二个完全没有必要,和第一个没有任何区别,除了加了一个没用的Lock。

你的第二种是和著名的doouble lock check的模式弄混了。 (这里有Wiki:http://en.wikipedia.org/wiki/Double-checked_locking),但是Double Lock Check只是在Singleton变量是指针需要New的时候才需要。Lock的目的是防止两次 "new ",和析构没有任何关系。

另外现在也证明出来Double Lock Check也是有问题的 (这篇讲得比较清楚:http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html),所以如果你的Singleton不需要在主函数退出之前析构,第一种方法是最好最干净的。(Jave里面由于不支持静态分配Object空间,所以没法儿用)。
[解决办法]
存在问题 ...

情景:
该单例对象在第一次实例化的时候,
【还未实例化完成】
在另外一个线程中又进行了一个实例化 ...

OK, 重复构造了 ..
[解决办法]
可以使用 线程锁 保证线程同步,
但是 ...
[解决办法]
可以比较一下 “饿汉式”单例 和 “饱汉式”单例。



http://www.java114.com/content21/content2855.html


[解决办法]
单例模式完全剖析:
http://www.chinaaspx.com/archive/java/15008.htm
...


是一个系列文章,楼主不妨研究研究 ···
[解决办法]
星辰再好好想想。。。

静态变量是CRT在调入你的主函数之前就被构造了,这个时候不可能出现第二个线程。等你的程序有机会调用Instance的时候,构造早已经完成了。

建议两位先自己试验一下,在你这个Singleton的构造函数和析构函数都设个断点,然后Debug一下,看什么时候ctor和dtor被调到,就知道了。同时也对Runtime的流程明白很多。
[解决办法]
静态变量是CRT在调入你的主函数之前就被构造了,这个时候不可能出现第二个线程。等你的程序有机会调用Instance的时候,构造早已经完成了。
=======>
函数内的局部静态对象是在是在函数第一次被使用时构造的!
[解决办法]
楼主的程序写法有小错误,现在这个写法当然是调用Instance的时候写(定义成函数静态了,应该是类静态),正确的Singleton写法是:

class singleton
{
public:
static singleton& instance()
{
return object;
}
static singleton object;
};
singleton singleton::object;

调用的时候用 singleton::instance();

我所有的讨论是基于这个。
[解决办法]
再补一句,Singleton实施的一个很重要的目标是不能每次在叫instance( ) 的时候撞到Lock,这样程序效率就很低,所以要尽可能的不Lock。你看楼主的第二种做法,Lock是在if程序里面,这样保证只Lock一次,就是这个目的。当然,这种情况最好的就是一次也不要Lock。
[解决办法]
CQZE,你的第二种写法既对,也不一定对,如果你想Lazy Initialization的话,必须Lock一次。其实你这个和Double lock check是一个意思。虽说Double Check Lock里面说的是动态分配,但是你如果定义成函数静态变量,其实也是很类似动态分配,第一次用的时候调用构造函数。

说不一定对,是象我所给的第二个Link所说,这种模式在多处理器没有Memory Barrier的情况下有失败的可能。所以如果Lazy Initialization的好处不大的情况下,直接定义Class静态变量是最省力的办法。(当然如果你的Initialization代价比较大,比如建立数据库连接,等等,另当别论)
[解决办法]
小鸡,翻短歌 blog 没?
[解决办法]
singlton是用得最多,又最没用,还又最难实现的一个模式。
建议不要钻得太深。《Modern c++ Design》和《Pattern Hatching》系列文章看过也就可以了。
[解决办法]
mark
[解决办法]
狒狒说,可以参考这个帖子:
http://blog.csdn.net/plainsong/archive/2003/11/27/16268.aspx
[解决办法]
怎么可能是两个???

guard_lock(mutex); //pseudo code //使用了线程锁
if(refer == 0)
{
static singleton object; //static 实力,打死都是1个
refer = &object;
return object;

[解决办法]
boost中的singleton的方法值得借鉴。虽然不能用lazy-initializtion,但是构造和访问效率很高,无须线程锁,无须双测试,无须公有构造函数,无须堆分配。所以,如果是程序中必须使用的singleton,建议使用这种方式。

template <typename T>
struct singleton
{
private:
struct object_creator
{
object_creator() { singleton <T> ::instance(); }
inline void do_nothing() const { }
};
static object_creator create_object;
singleton();
public:
typedef T object_type;
static object_type & instance()
{
static object_type obj;
create_object.do_nothing();
return obj;
}
};

template <typename T> typename singleton <T> ::object_creator singleton <T> ::create_object;

------解决方案--------------------


object_creator使得instance中的obj可以在进入main之前被构造出来,从而不必担心多线程的问题。因此,此后每次调用instance函数时都是“do_nothing”的,不用线程锁等等花费时间的做法。
[解决办法]
第二个不是很好吗
[解决办法]
是地,第二个是很好的。在需要lazy-initializtion时,应该用第二种方法。
不过有个笔误:
static singleton* refer;
if(refer == 0) // 应该是==,不能是!=

这是Double Check Lock的标准做法,适合多线程下的lazy-initializtion 。

至于多处理器和Memory Barrier,我想在多线程多处理器的情况下,还是要用Memory Barrier的(或类似的其他机制)。否则很多地方都会出问题,不仅仅是lazy-initializtion一个。

在不需要lazy-initializtion时,我觉得还是boost的做法最好,呵呵。

热点排行