排行榜 统计
  • 文章总数:665 篇
  • 评论总数:980 条
  • 分类总数:4 个
  • 最后更新:3月12日
none

c 线程安全的单例模式-设计模式之单例模式(C++版)

本文阅读 4 分钟
首页 正文
本文最后更新于2022年12月09日,已超过111天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

您阅读这篇文章共耗时:

  什么是单例模式?

  单例模式是为确保一个类只有一个实例,并为整个系统提供一个全局访问点的一种模式方法。

  单例特点:

  1 在任何情况下,单例类永远只有一个实例存在。

  2 单例需要有能力为整个系统提供这一唯一实例。

  示例:打印机,任务管理器等。

  实现一(单线程使用,多线程不安全)

   #include

    using namespace std;
    class Singleton
    {
    private:
        Singleton(){}
    public:
        static Singleton* instance()
        {
            if(_instance == 0)
                _instance = new Singleton();
            return _instance;
        }
    private:
        static Singleton* _instance;
    };
    Singleton* Singleton::_instance = 0;

  上面这种实现在单线程环境下是没有问题的,可是多线程下就有问题了。

  分析:

  1 线程A进入函数执行判断语句,这句执行后就挂起了,这时线程A已经认为为NULL,但是线程A还没有创建对象。

  2 又有一个线程B进入函数执行判断语句,此时同样认为变量为null,因为A没有创建对象。线程B继续执行,创建了一个对象。

  3 稍后,线程A接着执行,也创建了一个新的对象。

  4 创建了两个对象!

  从上面分析可以看出,需要对变量加上互斥锁:

  实现二(多线程安全,加锁代价高)

   #include

    #include 
    using namespace std;
    std::mutex mt;
    class Singleton
    {
    private:
        Singleton(){}
    public:
        static Singleton* instance()
        {
            mt.lock();  // 加锁
            if(_instance == 0)
                _instance = new Singleton();
            mt.unlock();  // 解锁
            return _instance;
        }
    private:
        static Singleton* _instance;
    };
    Singleton* Singleton::_instance = 0;

  上锁后是解决了线程安全问题,但是有些资源浪费。稍微分析一下:每次函数调用时候都需要请求加锁,其实并不需要,函数只需第一次调用的时候上锁就行了。这时可以用DCLP解决。

  实现三(双检查锁,由于内存读写导致不安全)

  Double-

   #include

    #include 
    using namespace std;
    std::mutex mt;
    class Singleton
    {
    
    private:
        Singleton(){}
    public:
        static Singleton* instance()
        {
            if(_instance == 0)
            {
                mt.lock();
                if(_instance == 0)
                    _instance = new Singleton();
                mt.unlock();
            }
            return _instance;
        }
    private:
        static Singleton* _instance;
    public:
        int atestvalue;
    };
    Singleton* Singleton::_instance = 0;

  这个版本很不错,又叫“双重检查”Double-Check。下面是说明:

  第一个条件是说,如果实例创建了,那就不需要同步了,直接返回就好了。不然,我们就开始同步线程。第二个条件是说,如果被同步的线程中,有一个线程创建了对象,那么别的线程就不用再创建了。

  分析

  _instance = new Singleton();

  为了执行这句代码,机器需要做三样事儿:

  1.对象分配空间。

  2.在分配的空间中构造对象

  3.使指向分配的空间

  遗憾的是编译器并不是严格按照上面的顺序来执行的。可以交换2和3.

  将上面三个步骤标记到代码中就是这样:

   Singleton* Singleton::instance() {

    
        if (_instance == 0) {
            mt.lock();
            if (_instance == 0) {
                _instance = // Step 3
                operator new(sizeof(Singleton)); // Step 1
                new (_instance) Singleton; // Step 2
            }
            mt.unlock();
        }
        return _instance;
    }

  实现四(C++ 11版本最简洁的跨平台方案)(推荐版本)

  Meyers

  局部静态变量不仅只会初始化一次,而且还是线程安全的。

#include using namespace std; class Singleton { public: // 注意返回的是引用 static Singleton& getInstance() { static Singleton value; //静态局部变量 return value; } private: Singleton() = default; Singleton(const Singleton& other) = delete; //禁止使用拷贝构造函数 Singleton& operator=(const Singleton&) = delete; //禁止使用拷贝赋值运算符 }; int main() { Singleton& s1 = Singleton::getInstance(); cout [1]: https://xuan.ddwoo.top/index.php/archives/556/ [2]: https://xuan.ddwoo.top/index.php/archives/558/ [3]: https://xuan.ddwoo.top/index.php/archives/549/ [4]: https://xuan.ddwoo.top/index.php/archives/555/  
本文来自投稿,不代表本站立场,如若转载,请注明出处:https://xuan.ddwoo.top/index.php/archives/561/
-- 展开阅读全文 --
中文编程语言有哪些-为什么 Python 不是未来的编程语言?
« 上一篇 12-08
aop事务管理-Spring事务实现原理
下一篇 » 12-09
------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

发表评论

本站已加入互联网信息服务许可,请规范您的言行哦~

成为第一个评论的人

作者信息

热门文章

珍惜时间哦~

今日一言

- -
加载中...
换一句

今日天气

标签TAG

热评文章