复杂的Singleton

//不包含成员初始化的Singleton
CObjFactory& CObjFactory::Instance()
{
 static CObjFactoryinstance;
 return instance;
}


//包含成员初始化的Singleton
CEngineManager& CEngineManager::Instance()
{
 static CEngineManagers_kbEngineMgr;

 try
 {
  if(s_kbEngineMgr.m_bInited)
  {
            return s_kbEngineMgr;
  }
  else
  {
   s_kbEngineMgr.m_sec.Lock();
   if(!s_kbEngineMgr.m_bInited)
   {
    s_kbEngineMgr.m_kbReasoningMgr.Release();
    CInnerManager::Instance().Release();
    s_kbEngineMgr.LoadBuffParam();
   ...
}


 

两种用法在单线程里都不会有什么问题
但是并发的时候 这两种方式都会存在严重的问题


 首先明确一点 static 定义的变量只会初始化一次
 
 先来看第一个例子
 加入有两个线程都调用了CObjFactory& CObjFactory::Instance();
 
 那么将会发生如下情况
 第一个线程执行到了static CObjFactoryinstance;
 调用了CObjFactory的构造函数 加入在构造函数执行到一般的时候发生了context swtich 构造函数并没有执行完毕
 而第二线程在这时进入了CObjFactory& CObjFactory::Instance()
 由于static的定义
 static CObjFactoryinstance;这句语句并不会被二次执行
 第二个线程直接返回return instance;
 
 如果这时对返回的对象调用成员函数会有如下两种情况
 1.没有访问成员变量的成员函数
  这不会造成什么问题
 2.有访问成员变量的成员函数
  程序崩溃
 
 原因很简单 由于第一个线程进入了CObjFactory的构造函数 但在构造函数还没执行完毕的时候发生了context switch 这时候对象的成员变量没有完全构造完成
 第二个线程抢占了执行权 这就有可能访问到尚未构造完成的成员变量 后果可想而知
 
 而二个Singleton的实现 自己对照第一种方式来解释 也将产生一样的问题


 造成bug的关键点在于构造函数是否完成没有一个明确的标识 不建议使用static 对象的方式来进行Singleton实现
      如果使用指针 根据指针是否为空则可以明确判断构造函数是否调用完成
  
 //remark reference from http://www.cppblog.com/ant/archive/2007/09/07/31786.html
 Double-Checked Locking机制看起来像是一个完美的解决方案,但是在某些条件下仍然不行。简单的说,编译器为了效率可能会重排指令的执行顺序(compiler-based reorderings)。看这一行代码:

 _instance = new Singleton();

 在编译器未优化的情况下顺序如下:
 1.new operator分配适当的内存;
 2.在分配的内存上构造Singleton对象;
 3.内存地址赋值给_instance。

 但是当编译器优化后执行顺序可能如下:
 1.new operator分配适当的内存;
 2.内存地址赋值给_instance;
 3.在分配的内存上构造Singleton对象。

 当编译器优化后,如果线程一执行到2后被挂起。线程二开始执行并发现0 == _instance为false,于是直接return,而这时Singleton对象可能还未构造完成,后果...

 上面说的还只是单处理器的情况,在多处理器(multiprocessors)的情况下,超线程技术必然会混合执行指令,指令的执行顺序更无法保障。关于Double-Checked Locking的更详细的文章,请看:
 The "Double-Checked Locking is Broken" Declaration
 http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
 
 
Singleton的析构问题
到此Singleton已经算比较完善了,但是依然算不上完美,因为到现在只是解决了多线程问题,加入了模板支持,对于KDL problem(The Dead Reference Problem)依然没法解决,可以说在实现Singleton模式时,最大的问题就是多个有依赖关系的Singleton的析构顺序。虽然Modern C++ Design中给出了解决方案,但是Loki的实现太过复杂,在此就不详细说明了,有兴趣的可以看看Modern C++ Design,当然了,Loki库中用策略模式实现的Singleton也很不错!

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值