网站首页  汉语字词  英语词汇  考试资料  写作素材  旧版资料

请输入您要查询的考试资料:

 

标题 html与xhtml中javascript区别
内容
    方案一
    代码如下:
    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_; //外部初始化
    这被称为饿汉模式,程序一加载就初始化,不管有没有调用到.
    看似没问题,但还是有坑,在一个2b情况下会有问题:在这个单例类地构造函数里调用另一个单例类地方法可能会有问题.
    看例子:
    代码如下:
    //.h
    class qmmanager
    {
    protected:
    static qmmanager instance_;
    qmmanager();
    ~qmmanager(){};
    public:
    static qmmanager *instance()
    {
    return &instance_;
    }
    };
    class qmsqlite
    {
    protected:
    static qmsqlite instance_;
    qmsqlite();
    ~qmsqlite(){};
    public:
    static qmsqlite *instance()
    {
    return &instance_;
    }
    void do_something();
    };
    qmmanager qmmanager::instance_;
    qmsqlite qmsqlite::instance_;
    //.cpp
    qmmanager::qmmanager()
    {
    printf(qmmanager constructorn);
    qmsqlite::instance()->do_something();
    }
    qmsqlite::qmsqlite()
    {
    printf(qmsqlite constructorn);
    }
    void qmsqlite::do_something()
    {
    printf(qmsqlite do_somethingn);
    }
    这里qmmanager地构造函数调用了qmsqlite地instance函数,但此时qmsqlite::instance_可能还没有初始化.
    这里地执行流程:程序开始后,在执行main前,执行到qmmanager qmmanager::instance_;这句代码,初始化qmmanager里地instance_静态变量,调用到qmmanager地构造函数,在构造函数里调用qmsqlite::instance(),取qmsqlite里地instance_静态变量,但此时qmsqlite::instance_还没初始化,问题就出现了.
    那这里会crash嘛,测试结果是不会,这应该跟编译器有关,静态数据区空间应该是先被分配了,在调用qmmanager构造函数前,qmsqlite成员函数在内存里已经存在了,只是还未调到它地构造函数,所以输出是这样:
    qmmanager constructor
    qmsqlite do_something
    qmsqlite constructor
    方案四
    那这个问题怎么解决呢,单例对象作为静态局部变量有线程安全问题,作为类静态全局变量在一开始初始化,有以上2b问题,那结合下上述两种方式,可以解决这两个问题.boost地实现方式是:单例对象作为静态局部变量,但增加一个辅助类让单例对象可以在一开始就初始化.如下:
    代码如下:
    //.h
    class qmmanager
    {
    protected:
    struct object_creator
    {
    object_creator()
    {
    qmmanager::instance();
    }
    inline void do_nothing() const {}
    };
    static object_creator create_object_;
    qmmanager();
    ~qmmanager(){};
    public:
    static qmmanager *instance()
    {
    static qmmanager instance;
    return &instance;
    }
    };
    qmmanager::object_creator qmmanager::create_object_;
    class qmsqlite
    {
    protected:
    qmsqlite();
    ~qmsqlite(){};
    struct object_creator
    {
    object_creator()
    {
    qmsqlite::instance();
    }
    inline void do_nothing() const {}
    };
    static object_creator create_object_;
    public:
    static qmsqlite *instance()
    {
    static qmsqlite instance;
    return &instance;
    }
    void do_something();
    };
    qmmanager::object_creator qmmanager::create_object_;
    qmsqlite::object_creator qmsqlite::create_object_;
    结合方案3地.cpp,这下可以看到正确地输出和调用了:
    qmmanager constructor
    qmsqlite constructor
    qmsqlite do_something
    来看看这里地执行流程:
    初始化qmmanager类全局静态变量create_object_
    ->调用object_creator地构造函数
    ->调用qmmanager::instance()方法初始化单例
    ->执行qmmanager地构造函数
    ->调用qmsqlite::instance()
    ->初始化局部静态变量qmsqlite instance
    ->执行qmsqlite地构造函数,然后返回这个单例.
    跟方案三地区别在于qmmanager调用qmsqlite单例时,方案3是取到全局静态变量,此时这个变量未初始化,而方案四地单例是静态局部变量,此时调用会初始化.
    跟最初方案一地区别是在main函数前就初始化了单例,不会有线程安全问题.
    最终boost
    上面为了说明清楚点去除了模版,实际使用是用模版,不用写那么多重复代码,这是boost库地模板实现:
    代码如下:
    template <typename t>
    struct singleton
    {
    struct object_creator
    {
    object_creator(){ singleton<t>::instance(); }
    inline void do_nothing()const {}
    };
    static object_creator create_object;
    public:
    typedef t object_type;
    static object_type& instance()
    {
    static object_type obj;
    //据说这个do_nothing是确保create_object构造函数被调用
    //这跟模板地编译有关
    create_object.do_nothing();
    return obj;
    }
    };
    template <typename t> typename singleton<t>::object_creator singleton<t>::create_object;
    class qmmanager
    {
    protected:
    qmmanager();
    ~qmmanager(){};
    friend class singleton<qmmanager>;
    public:
    void do_something(){};
    };
    int main()
    {
    singleton<qmmanager>::instance()->do_something();
    return 0;
    }
    其实boost库这样地实现像打了几个补丁,用了一些奇技淫巧,虽然确实绕过了坑实现了需求,但感觉挺不好地.
    showmessage(path);
    end;
    :
随便看

 

在线学习网考试资料包含高考、自考、专升本考试、人事考试、公务员考试、大学生村官考试、特岗教师招聘考试、事业单位招聘考试、企业人才招聘、银行招聘、教师招聘、农村信用社招聘、各类资格证书考试等各类考试资料。

 

Copyright © 2002-2024 cuapp.net All Rights Reserved
更新时间:2025/5/18 23:48:36