免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1727 | 回复: 5
打印 上一主题 下一主题

关于Singleton模式的一个问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-09 11:25 |只看该作者 |倒序浏览
刚好在看singleton这个pattern
我一般是这样做的,不知道在多线程下边有没有问题:
#include <iostream>
using std::cout;
using std::endl;

class Singleton
{
public:
  bool loadConfig()
  {
    cout << "Load Config" << endl;
    return true;
  }
  
  static Singleton &instance()
  {
    static Singleton inst;
    Singleton *pInst = &inst;
    return *pInst;
  }
protected:
  Singleton()
  {
    cout << "In Singleton" << endl;
  }
  ~Singleton()
  {
    cout << "In ~Singleton" << endl;
  }

private:
  //not available
  Singleton(const Singleton &inst);
  Singleton &operator=(const Singleton &inst);
};

int main()
{
  Singleton::instance().loadConfig();
}

书上提到了在多线程的情况下,可以使用Double-Checked Locking的方法来实现线程安全,同时可以保证效率,好像也是容易的.
我就是不太明白,好像我在函数里边用个静态变量的方法应该也是可以保证的吧.C++自己去初始化这个变量应该自己可以保证是线程安全的吧?
就是这个问题不是很确定,哪个兄弟指点一下.

论坛徽章:
0
2 [报告]
发表于 2009-03-09 11:32 |只看该作者
可以,只不过他们对象创建的时间不同而已,一个是编译时确定(eg.对象较小且一定会用到),一个是运行时确定(eg.对象较大且未必会用到),看你的需求选择

static class *p = new calss();

[ 本帖最后由 alexhappy 于 2009-3-9 11:36 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2009-03-09 11:34 |只看该作者
Double-Checked Locking说到底还是使用了mutex之类的东西用于保证多线程下的安全。如果不用mutex的话,也有办法,但是不是你这个办法。
你在函数内部定义静态变量,该变量会在第一次调用instance的时候被初始化,是无法保证安全的。因为可能会存在两个线程都调用这个函数。
要保证线程安全,可以让你的这个静态变量在main函数之前被初始化。

论坛徽章:
0
4 [报告]
发表于 2009-03-09 11:39 |只看该作者

回复 #3 kevinlynx 的帖子

就是说
  static Singleton &instance()
  {
    static Singleton inst;
    Singleton *pInst = &inst;
    return *pInst;
  }
如果两个线程差不多同时进来的话,也会产生两个对像,然后有一个线程拿到的结果和其它的线程的结果是不一样的?
如果真是这样的话,就感觉有点诡异了

论坛徽章:
0
5 [报告]
发表于 2009-03-09 11:51 |只看该作者

回复 #4 fanhongxuan 的帖子

不是。对象还是一个,因为只有一个函数。这就像一般的书上讲多线程访问同一个变量一样。也就是说:

//thread 1
Singleton::instance();

//thread 2
Singleton::instance();

如果线程1先获得执行权,instance第一次执行,那么准备初始化static Singleton inst;中的inst,但是当初始化一半的时候,线程2被调度获得执行权,线程1挂起,线程2调用instance函数时,就不知道inst是否被完全初始化完毕,这里就可能会出现问题。

所以,在boost中的singleton中,对于多线程的singleton,它的实现大致为:


  1. template <typename _Tp>
  2. class CMTSingleton
  3. {
  4. private:
  5.     class Creator
  6.    {
  7.    public:
  8.          Creator() { CMTSingleton<_Tp>::instance(); }
  9.          inline void DoNothing() const { }
  10.     }

  11.    static Creator creator;
  12. };

  13. template <typename _Tp>
  14. typename CMTSingleton<_Tp>::Creator CMTSingleton<_Tp>::creator;

复制代码


creator为全局静态变量,所以它会在main之前被初始化,creator初始化时,其构造函数中调用了instance函数,那么就可以保证你代码中的static Singleton inst;在被任何线程访问之前首先被初始化。这样,在以后的访问中,它就是线程安全的。

建议google boost中singleton的具体实现。
对于double-checking-locked,可以参看loki的singleton实现。

[ 本帖最后由 kevinlynx 于 2009-3-9 11:52 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2009-03-10 10:20 |只看该作者
要不要lock
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP