1、简单的单例模式实现

2、C++的构造函数不是线程安全的,所以上述代码在多线程的情况下是不安全的,原因是new Singelton时,这句话不是原子的,比如一个线程执行了new的同时,另一个线程对if进行判断(此时实例还没被创建出来)。在windows下模拟:

#include <iostream>
#include <process.h>
#include <windows.h>
using namespace std; class Singelton{
private:
Singelton(){
m_count ++;
printf("Singelton begin\n");
Sleep(1000); // 加sleep为了放大效果
printf("Singelton end\n");
}
static Singelton *single;
public:
static Singelton *GetSingelton();
static void print();
static int m_count;
}; Singelton *Singelton::single = nullptr;
int Singelton::m_count = 0; Singelton *Singelton::GetSingelton(){
if(single == nullptr){
single = new Singelton;
}
return single;
} void Singelton::print(){
cout<<m_count<<endl;
}
// 回调函数
void threadFunc(void *p){
DWORD id = GetCurrentThreadId(); // 获得线程id
cout<<id<<endl;
Singelton::GetSingelton()->print(); // 构造函数并获得实例,调用静态成员函数
} int main(int argc, const char * argv[]) {
int threadNum = 3;
HANDLE threadHdl[100]; // 创建3个线程
for(int i = 0; i<threadNum; i++){
threadHdl[i] = (HANDLE)_beginthread(threadFunc, 0, nullptr);
} // 让主进程等待所有的线程结束后再退出
for(int i = 0; i<threadNum; i++){
WaitForSingleObject(threadHdl[i], INFINITE);
}
cout<<"main"<<endl; // 验证主进程是否是最后退出
return 0;
}

  运行结果:

该单例模式也称为懒汉式单例。

懒汉:故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化。与之对应的是饿汉式单例。(注意,懒汉本身是线程不安全的,如上例子)

饿汉:饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。(本身就是线程安全的,如下例子)

关于如何选择懒汉和饿汉模式:

特点与选择:

  懒汉:在访问量较小时,采用懒汉实现。这是以时间换空间。

  饿汉:由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。

3、饿汉式的单例实现

#include <iostream>
#include <process.h>
#include <windows.h>
using namespace std; class Singelton{
private:
Singelton(){
m_count ++;
printf("Singelton begin\n");
Sleep(1000); // 加sleep为了放大效果
printf("Singelton end\n");
}
static Singelton *single;
public:
static Singelton *GetSingelton();
static void print();
static int m_count;
};
// 饿汉模式的关键:初始化即实例化
Singelton *Singelton::single = new Singelton;
int Singelton::m_count = 0; Singelton *Singelton::GetSingelton(){
// 不再需要进行实例化
//if(single == nullptr){
// single = new Singelton;
//}
return single;
} void Singelton::print(){
cout<<m_count<<endl;
}
// 回调函数
void threadFunc(void *p){
DWORD id = GetCurrentThreadId(); // 获得线程id
cout<<id<<endl;
Singelton::GetSingelton()->print(); // 构造函数并获得实例,调用静态成员函数
} int main(int argc, const char * argv[]) {
int threadNum = 3;
HANDLE threadHdl[100]; // 创建3个线程
for(int i = 0; i<threadNum; i++){
threadHdl[i] = (HANDLE)_beginthread(threadFunc, 0, nullptr);
} // 让主进程等待所有的线程结束后再退出
for(int i = 0; i<threadNum; i++){
WaitForSingleObject(threadHdl[i], INFINITE);
}
cout<<"main"<<endl; // 验证主进程是否是最后退出
return 0;
}

  运行结果:

4、线程安全的懒汉式单例的实现

饿汉式会提前浪费我们的内存空间以及资源,如果有项目中要求我们在使用到实例的时候再去实例化,则还是需要使用懒汉式。

class singleton
{
protected:
singleton()
{
// 初始化
pthread_mutex_init(&mutex);
}
private:
static singleton* p;
public:
static pthread_mutex_t mutex;
static singleton* initance();
}; pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
if (p == NULL)
{
// 加锁
pthread_mutex_lock(&mutex);
if (p == NULL)
p = new singleton();
pthread_mutex_unlock(&mutex);
}
return p;
}

  需要注意的是:上面进行的两次if(p == NULL)的检查,因为当获得了实例之后,有了外层的判断之后,就不会再进入到内层判断,即不会再进行lock以及unlock的操作。

C++ 单例模式(懒汉、饿汉模式)的更多相关文章

  1. java 设计模式 单例模式之饿汉模式/懒汉模式 singleton pattern

    https://v.qq.com/x/page/e0364ung5zp.html 讲的不错, 关于 饿汉式单例模式 code Student 类: package com.test;//单例模式之   ...

  2. Java单例模式之饿汉模式与懒汉模式

    单例模式是我们在开发软件的过程中经常用到的23中常用的java模式之一,主要的功能就是保证我们所使用的对象只有一个,这也在一方面减少了出错的可能性,增强了代码的健壮.单例模式一般来说有两种实现的方式, ...

  3. Java-设计模式-单例模式-饿汉模式、懒汉模式

    //-------------------------------------------------------------饿汉模式--开始----------------------------- ...

  4. java 单例模式之线程安全的饿汉模式和懒汉模式

    转载博主:thankyou https://blog.csdn.net/twj13162380953/article/details/53869983 理解: 饿汉式获取实例的步骤简单所以线程更安全. ...

  5. C++的单例模式与线程安全单例模式(懒汉/饿汉)

    1 教科书里的单例模式 我们都很清楚一个简单的单例模式该怎样去实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实例,实 ...

  6. javascript单例模式(懒汉 饿汉)

    第一种:懒汉模式 var Singleton=(function(){ var instantiated; //比较懒,在类加载时,不创建实例,因此类加载速度快,但运行时获取对象的速度慢 functi ...

  7. Java:Java单例中的懒汉和饿汉模式

    1.懒汉模式 懒汉模式:在类加载的时候不被初始化,懒汉式是延时加载,他是在需要的时候才创建对象. public class JdbcUtil { //定义私有的引用 private static Jd ...

  8. java单例,懒汉&饿汉

     * 单例模式Singleton  * 应用场合:有些对象只需要一个就足够了,如皇帝  * 作用: 保证整个应用程序中某个实例有且只有一个  * 区别: 饿汉模式的特点是加载类时比较慢,但运行是比较快 ...

  9. 设计模式(一)单例模式:2-懒汉模式(Lazy)

    思想: 相比于饿汉模式,懒汉模式实际中的应用更多,因为在系统中,“被用到时再初始化”是更佳的解决方案. 设计思想与饿汉模式类似,同样是持有一个自身的引用,只是将 new 的动作延迟到 getinsta ...

随机推荐

  1. WDA-4-ALV按钮&ICON

    1.ICON图标 AccessControlledArea (14x14) Activate (14x14) Active (14x14) AdaptationTechnical (14x14) Ad ...

  2. LeetCode题解:Flatten Binary Tree to Linked List:别人的递归!

    总是在看完别人的代码之后,才发现自己的差距! 我的递归: 先把左侧扁平化,再把右侧扁平化. 然后找到左侧最后一个节点,把右侧移动过去. 然后把左侧整体移到右侧,左侧置为空. 很复杂吧! 如果节点很长的 ...

  3. React Native,flexbox布局

    Flexbox布局 flex:使组件在可利用的空间内动态地扩张或收缩.flex:1会使组件撑满空间.当有多个组件都指定了flex的值,那么谁的flex值大谁占得空间就大,占得大小的比例就是flex值的 ...

  4. Mac 命令行,自定义命令

    例如自定义命令 gotoXFolder, 直接进入XFolder文件夹, XFolder地址为~/abc/def/Xfolder 步骤: 1. 在home文件夹下创建.profile文件 在.prof ...

  5. Linux 循环创建多个线程

    这里说一下相关的基础知识: 线程概念 什么是线程 LWP:light weight process 轻量级的进程,本质仍是进程(在Linux环境下)     进程:独立地址空间,拥有PCB     线 ...

  6. getVisibleSize,getWinSize,getFrameSize,getViewPortRect

    cc.director.getVisibleSize();//获取运行场景的可见大小 cc.director.getWinSize();//获取视图的大小,以点为单位 cc.director.getW ...

  7. C# 简单的定时关机

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  8. HBuilder在MAC下的SVN

    1. 安装svn插件,工具--插件安装---svn--安装 2. 使用svn,文件---导入---从svn检出项目 -- 下一步 3. 创建新的资源库位置--下一步-- URL(输入svn仓库地址)- ...

  9. 魅族手机USB调试无法打开、log无法打印

    MEIZU 在打开usb调试允许时,总提示:because an app is oobscuring a premision request, Setting can't verify your re ...

  10. Socket通讯-Netty框架实现Java通讯

    Netty简介 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序. 也就是说,Netty ...