首页 > 网站 > 建站经验 > 正文

asp.net中C++单例实现、问题分析

2019-11-02 14:46:05
字体:
来源:转载
供稿:网友

   方案一

 代码如下   class QMManager
{
public:
    static QMManager &instance()
    {
        static QMManager instance_;
        return instance_;
    }
}

  这是最简单的版本,在单线程下(或者是C++0X下)是没任何问题的,但在多线程下就不行了,因为static QMManager instance_;这句话不是线程安全的。

  在局部作用域下的静态变量在编译时,编译器会创建一个附加变量标识静态变量是否被初始化,会被编译器变成像下面这样(伪代码):

 代码如下   static QMManager &instance()
{
    static bool constructed = false;
    static uninitialized QMManager instance_;
    if (!constructed) {
        constructed = true;
        new(&s) QMManager; //construct it
    }
    return instance_;
}

  这里有竞争条件,两个线程同时调用instance()时,一个线程运行到if语句进入后还没设constructed值,此时切换到另一线程,constructed值还是false,同样进入到if语句里初始化变量,两个线程都执行了这个单例类的初始化,就不再是单例了。

  方案二

  一个解决方法是加锁:

 代码如下   static QMManager &instance()
{
    Lock(); //锁自己实现
    static QMManager instance_;
    UnLock();
    return instance_;
}

  但这样每次调用instance()都要加锁解锁,代价略大。

  方案三

  那再改变一下,把内部静态实例变成类的静态成员,在外部初始化,也就是在include了文件,main函数执行前就初始化这个实例,就不会有线程重入问题了:

 代码如下   class QMManager
{
protected:
    static QMManager instance_;
    QMManager();
    ~QMManager(){};
public:
    static QMManager *instance()
    {
        return &instance_;
    }
    void do_something();
};
QMManager QMManager::instance_; //外部初始化

  这被称为饿汉模式,程序一加载就初始化,不管有没有调用到。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表