zoukankan      html  css  js  c++  java
  • (载)对于c++中实现单例的讨论

    C++中实现单例,需要注意两个问题:1.对内存的释放。2.多线程下的健壮性。

    以下是CSDN上对于此问题的讨论,先存一个。

     
    #9楼 得分:5回复于:2008-02-18 20:26:40
    你这个方法实现singleton不太好,会有多线程同步问题。
    比如说一开始Singleton::instance为空。然后有线程A和线程B同时访问Singleton::GetInstance()。
    有意思的是当任务A执行if (NULL == instance)这句时,刚判断好instance确实为空想调用new,或者时间可以再放款到正在执行new操作,但是还没有返回;要命的是调度器由于某些原因一下子剥夺了线程A的执行又去执行线程B了。线程B顺利地创建了一个instance实例,然后在某一时刻被调度器剥夺,再次执行线程A。OK,此时线程A从刚才的混沌中继续执行它的new Singleton()的操作,这样线程A所创建出来的就是另一个实例了。此时Singleton宣告破灭。

    因此,能够迎合多线程,乃至多处理的单件处理可以用以下方式:

    C/C++ code
     class Singleton  
    {  
     private:  
       static Singleton instance;  
      Singleton(void) {}  
     public:  
      static Singleton& GetInstance()  
      {
         return instance;
      }
    };
    Singleton Singleton::instance;

    由于以上代码中,Singleton::instance在程序加载后由初始化程序建立,因此对于应用程序不会有多线程困扰。如果是在多处理器或多核处理器环境下还要注意Singleton的成员函数中的一些同步。

     
     
     
    #10楼 得分:0回复于:2008-02-18 20:35:14
    回复Jim_King_2000:

    在C++中使用singleton不用new主要不是因为要担心如何delete。
    如果你的应用程序指明了一个接收到一个消息,由专门一个任务相应析构这个singleton实例,可以显式地调用其析构函数:Singleton::GetInstance().~Singleton();
    个人认为多任务机制下,用楼主的方法不太合适。而Jim_King_2000你的方法也有多线程问题。
    因为局部static也不会对实例创建的操作原子化,除非构造函数内部具有锁机制。或者也是通过某种消息相应或通过状态表示要创建一个Singleton实例,以确保在第一次调用Singleton::GetInstance()时只有一个任务执行,且操作过程中不被打断,至少被打断后不会被重入。

     
     
     
    #14楼 得分:0回复于:2008-02-19 08:40:39
    感谢各位的精彩回复,让在下获益匪浅啊。

    liuworld说得确实是,静态成员变量必须要在具体的cpp文件中进行定义,类中出现的静态成员变量只表示一种声明。

    感谢zenny-chen的提醒,我这种写法在多线程环境下确实会有潜在问题,这是一种“恶汉式”的单例模式,就是需要的时候才创建实例,你提供的实现是一种“懒汉式”的单例模式,就是程序初始化加载的时候就首先创建好实例,然后每次引用即可。这确实可以解决一些多线程调度的问题,但是会提前占用系统资源,当然,一般来说,“恶汉式”的单例模式已经基本上可以满足我们的需求了。

    对于“懒汉式”的单例模式,可以使用锁和双重判断的方式来避免重复创建的问题。

    例如:
      static Singleton *GetInstance()   
      {   
      if (NULL == instance)   
      {   
      lock()
      {   
      if (instance == NULL)   
      instance = new Singleton();   
      }  
      }   
      return instance;   
      }

     
     
     
    #15楼 得分:0回复于:2008-02-19 08:56:27
    还是去看《Modern C++ Design》吧。
    另外,google "Pattern Hatching",等,纯C、C++语言是无法安全实现多线程安全的singleton的。
    勉强够用的实现就可以了。
     
     
     
    #16楼 得分:0回复于:2008-02-19 11:08:55
    to zenny_chen:
    你的方法有效率问题。只要使用了你的类,这个静态对象都会被创建,无论该对象是否被用户使用。如果该对象的构造和析构十分费时的话,这样的方法会使效率大大降低。况且你的方法也并不能保证多线程安全。你怎么知道静态的instance在构造的时候没有别的线程正在调用GetInstance函数?

    ===========================================================================
    如果你的应用程序指明了一个接收到一个消息,由专门一个任务相应析构这个singleton实例,可以显式地调用其析构函数:Singleton::GetInstance().~Singleton();  
    ===========================================================================
    如果应用程序没有用消息怎么办?就算使用了消息,你怎么知道其它线程不需要Singleton对象了?万一程序非正常退出怎么办(比如遇到未处理的异常或者非法操作)?

    ===========================================================================
    而Jim_King_2000你的方法也有多线程问题。  
    ===========================================================================
    1、我真的很希望这是我的方法。可惜现实不是这样。这个方法属于Scott Meyers。
    2、这个方法是实现singleton的基础。很多种singleton实现(如相互依赖的singleton,多线程下的singleton等等)都是依据这个方法实现的。
    3、很多实现在一开始的时候并不考虑多线程。等到单线程的实现方法出来以后,再扩展到多线程上面或者由用户自行加锁。STL也并不是多线程的。但这并不影响使用,你自己加锁就是了。

    所以说singleton里面不用new并不是因为多线程。而是没有必要用new。建议你也翻翻《Modern C++ Design》。里面有多线程singleton的实现。

     
     
     
    #17楼 得分:0回复于:2008-02-19 20:19:58
    To 楼上:

    呵呵,在大多数场合我要让应用程序一直使用这个Singleton实例。因此,我将它放在全局数据存储区是个不错的主意,尤其在嵌入式系统中甚至可以将它放入ROM中。因此,在嵌入式系统中,这个实例在机器引导后就存在了,直到复位或关机。所以你说我还要对它在程序运行时进行创建或析构就显得荒谬了。

    而本人没那么多时间去读那些号称为C++大师们写的东西,我感兴趣的部分是基于多核处理器的操作系统以及并行计算,和人工智能等问题。

     
     
     
    #18楼 得分:0回复于:2008-02-20 13:53:25
    to 楼上:
    ==========================================
    在大多数场合我要让应用程序一直使用这个Singleton实例
    ==========================================
    我们不应该假设这样的场合。你的assumption不具有通用性。如果用户的程序需要运行时创建singleton或者根本不创建某个singleton对象会怎样?如果用户只需要创建几个不同的singleton对象中的一个或几个(非全部)会怎么样?

    ==========================================
    尤其在嵌入式系统中甚至可以将它放入ROM中
    ==========================================
    同样,这仍然不具有通用性。Singleton是可以根据需要创建的,这样会大大限制了singleton的使用场合。

    ==========================================
    因此,在嵌入式系统中,这个实例在机器引导后就存在了,直到复位或关机。所以你说我还要对它在程序运行时进行创建或析构就显得荒谬了。  
    ==========================================
    我们不应该假设这样的场合,用户的代码不一定运行在嵌入式系统上。就算是在嵌入式系统中,singleton仍然可以根据需要创建,Scott Meyers的方法也适用,我们只要在应用程序开始的时候调用初始化函数(也就是包含singleton对象的定义的那个函数)即可。

    ==========================================
    而本人没那么多时间去读那些号称为C++大师们写的东西
    ==========================================
    真没时间就算了,如果有时间的话,还是要看一下。我们学数学,看得就是大师们的成果;你学人工智能,书上的内容也是大师的成果;学C++也一样。

     
     
     
    #19楼 得分:0回复于:2008-02-20 13:53:44
    to 楼上:
    ==========================================
    在大多数场合我要让应用程序一直使用这个Singleton实例
    ==========================================
    我们不应该假设这样的场合。你的assumption不具有通用性。如果用户的程序需要运行时创建singleton或者根本不创建某个singleton对象会怎样?如果用户只需要创建几个不同的singleton对象中的一个或几个(非全部)会怎么样?

    ==========================================
    尤其在嵌入式系统中甚至可以将它放入ROM中
    ==========================================
    同样,这仍然不具有通用性。Singleton是可以根据需要创建的,这样会大大限制了singleton的使用场合。

    ==========================================
    因此,在嵌入式系统中,这个实例在机器引导后就存在了,直到复位或关机。所以你说我还要对它在程序运行时进行创建或析构就显得荒谬了。  
    ==========================================
    我们不应该假设这样的场合,用户的代码不一定运行在嵌入式系统上。就算是在嵌入式系统中,singleton仍然可以根据需要创建,Scott Meyers的方法也适用,我们只要在应用程序开始的时候调用初始化函数(也就是包含singleton对象的定义的那个函数)即可。

    ==========================================
    而本人没那么多时间去读那些号称为C++大师们写的东西
    ==========================================
    真没时间就算了,如果有时间的话,还是要看一下。我们学数学,看得就是大师们的成果;你学人工智能,书上的内容也是大师的成果;学C++也一样。

     
     
     
    #20楼 得分:0回复于:2008-02-21 18:27:14
    To Jim_King_2000 :

    实际上在你的代码中,由于使用了static,尽管在函数内,但是在加载器加载你的应用程序时仍然会为你的全局唯一的Singleton预留空间。只不过在调用GetInstance()时才调用构造函数(若有的话)。
    而我的方法是在加载应用程序后,在初始化代码中调用构造函数(如果有的话),但却带来了额外的安全性。实际上你所谓的存储空间效率两者是一样的,而且结束生命的时间也一样。除非你在构造函数中调用了内存动态分配函数,这样很显然,我的代码将在初始化过程中分配空间;而你的将在第一次调用GetInstance()时分配。

     
     
     
    #25楼 得分:0回复于:2008-02-22 13:44:54
    我想这里的 Singleton 是针对语言本身提出的解决方案;如果将之与系统相关的设计联系起来,未免有些牵强了。
    当然实际应用的时候首先考虑的是系统的设计,然后才是具体的解决方法,而这里的Singleton ,正是在C++中的
    解决方法之一。和系统相关的设计应该被分离出去。设计首先要保证 Singleton 的应用是系统安全的,不管是
    在何种环境下,这个条件成立以后,才会提到它的具体实现的设计——比如说这里的C++ Singleton 。否则,会把
    很多问题缠绕在一起,有时候根本不能解决问题
     
     
     
    #29楼 得分:0回复于:2008-11-18 09:27:49
    引用 4 楼 Jim_King_2000 的回复:
    兄弟,singleton是不用new的。如果用了new,在什么地方去delete它呢?singleton原理的基础是局部static变量。
    C/C++ codeclassSingleton 
    {private:staticSingleton*instance; 

    Singleton() 

    }public:staticSingleton*GetInstance() 
    {staticSingleton singleton;return&singleton

    };
    这种局部static变量只有在函数被调用的第一次才被创建,随着程序的结束而结束…

    private 保证只有一个实现,
    static data + static member function !=singleton,
    不容易销毁,那本书叫做 不死的凤凰
     
  • 相关阅读:
    mpstat命令学习
    vmstat命令学习
    Oracle数据库坏块的恢复
    Oracle数据库字符集试验
    记一次windows下物理迁移数据库的过程
    NeoKylin5.6下安装部署达梦(DM7)数据库
    使用BBED模拟Oracle数据库坏块
    centos7之zabbix的监控H3C ER3200G2流量
    centos7之zabbix3.2的fping监控
    centos7之zabbix3.2搭建
  • 原文地址:https://www.cnblogs.com/hummersofdie/p/1812454.html
Copyright © 2011-2022 走看看