摘自 java 设计模式官网 中 有关单例模式的定义:
Ensures that only one object of a particular class is ever created, and provide a global point of access to it
确保某个特定的类只被创建一次,并且提供一个全局的接口去访问实例。
提炼几点主要内容
系统中要求一个类只有一个对象时可采取单例模式,具体的以下场景:
大家可以自己实际情况进行分析,采用符合自己实际情况的模式
设计模式是Java中最经常使用的,而大多数的设计模式通常也是用Java实现的,设计模式更是一种编程思想,可以用任何的编程语言进行实现,只不过有的语言简单有的语言麻烦而已,本小结主要介绍单例模式的c++实现。
提到单例就不得不提到单例模式的两种实现方法:懒汉 和 饿汉
单例模式在单线程下不存在线程安全的问题,然而在多线程下就涉及到全局资源竞争问题,主要存在以下两个方面:
本博文主要讨论上述第一种线程安全问题。
利用static静态全局变量实现饿汉模式,代码如下:
SingletonHungry.h
#ifndef SINGLETON_HUNGRY_H
#define SINGLETON_HUNGRY_H
#include
class SingletonHungry
{
public:
static SingletonHungry * get_instance()
{
return & gcls_singleton_instance;
}
private:
// 静态的全局变量 声明为 私有 static 变量 防止外部进行访问
static SingletonHungry gcls_singleton_instance;
// 构造函数 析构函数 赋值 拷贝 函数 防止外部进行创建
SingletonHungry()
{
printf("%s %d create Singleton Hungry\n",__FUNCTION__,__LINE__);
};
~SingletonHungry()
{
printf("%s %d destroy Singleton Hungry\n",__FUNCTION__,__LINE__);
};
SingletonHungry(const SingletonHungry &);
SingletonHungry & operator=(const SingletonHungry &);
};
#endif
单例的使用
SingletonHungryMain.cpp
#include "SingletonHungry.h"
SingletonHungry SingletonHungry :: gcls_singleton_instance;
int main(void)
{
printf("Singleton Hungry test \n");
return 0;
}
编译运行:
root@wan:/wan/01singleton# make SingletonHungryMain
g++ SingletonHungryMain.cpp -o SingletonHungryMain
root@wan:/wan/01singleton# ./SingletonHungryMain
SingletonHungry 20 create Singleton Hungry
Singleton Hungry test
~SingletonHungry 24 destroy Singleton Hungry
通过上面代码可以饿汉模式是不需要考虑在创建时的线程安全问题,因为在程序启动之前,内存就已经分配完成,程序退出时自动进行析构;同样内存可以分配在堆上,同样是程序加载main函数之前进行new 等程序结束运行之前进行delete 这里就不进行详细的介绍,有一些可以自动释放堆内存的一些方法(智能指针、通过内部类的方式等),有机会进行详细介绍。
SingletonLazyV1.h
#ifndef SINGLETON_LAZY_H
#define SINGLETON_LAZY_H
#include
class SingletonLazy
{
public:
/*
多个线程同时调用该接口时存在线程安全问题:
问题出在 pgcls_singleton_instance = new SingletonLazy();
线程1 检查 pgcls_singleton_instance = NULL 然后进行 new 然而new还没有完成
此时线程2 同样也检测到 pgcls_singleton_instance = NULL 同样又去进行new,这样就会造成:
1、new了两次 造成内存泄漏
2、pgcls_singleton_instance被赋值了两次,从而早晨内存错乱。
*/
static SingletonLazy * get_instance()
{
if(NULL == pgcls_singleton_instance)
{
pgcls_singleton_instance = new SingletonLazy();
printf("%s %d new Singleton Lazy\n",__FUNCTION__,__LINE__);
}
else
{
printf("%s %d Singleton Lazy already \n",__FUNCTION__,__LINE__);
}
return pgcls_singleton_instance;
}
private:
// 静态的全局变量 声明为 私有 static 变量 防止外部进行访问
static SingletonLazy * pgcls_singleton_instance;
// 构造函数 析构函数 赋值 拷贝 函数 防止外部进行创建
SingletonLazy()
{
printf("%s %d create Singleton Lazy\n",__FUNCTION__,__LINE__);
};
~SingletonLazy()
{
printf("%s %d destroy Singleton Lazy\n",__FUNCTION__,__LINE__);
};
SingletonLazy(const SingletonLazy &);
SingletonLazy & operator=(const SingletonLazy &);
};
SingletonLazy * SingletonLazy :: pgcls_singleton_instance = NULL;
#endif
主程序
SingletonLazyV1Main.cpp
#include "SingletonLazyV1.h"
int main(void)
{
SingletonLazy:: get_instance();
SingletonLazy:: get_instance();
SingletonLazy:: get_instance();
return 0;
}
编译并运行
root@wan:/wan/01singleton# make SingletonLazyV1Main
g++ SingletonLazyV1Main.cpp -o SingletonLazyV1Main
root@wan:/wan/01singleton# ./SingletonLazyV1Main
SingletonLazy 30 create Singleton Lazy
get_instance 15 new Singleton Lazy
get_instance 19 Singleton Lazy already
get_instance 19 Singleton Lazy already
SingletonLazyV2.h
#ifndef SINGLETON_LAZY_H
#define SINGLETON_LAZY_H
#include
#include
class SingletonLazy
{
public:
/*
解决多线程调用时线程安全问题采用加锁的形式。
*/
static SingletonLazy * get_instance()
{
singleton_mutex.lock();
if(NULL == pgcls_singleton_instance)
{
pgcls_singleton_instance = new SingletonLazy();
printf("%s %d new Singleton Lazy\n",__FUNCTION__,__LINE__);
}
else
{
printf("%s %d Singleton Lazy already \n",__FUNCTION__,__LINE__);
}
singleton_mutex.unlock();
return pgcls_singleton_instance;
}
private:
static std::mutex singleton_mutex;
// 静态的全局变量 声明为 私有 static 变量 防止外部进行访问
static SingletonLazy * pgcls_singleton_instance;
// 构造函数 析构函数 赋值 拷贝 函数 防止外部进行创建
SingletonLazy()
{
printf("%s %d create Singleton Lazy\n",__FUNCTION__,__LINE__);
};
~SingletonLazy()
{
printf("%s %d destroy Singleton Lazy\n",__FUNCTION__,__LINE__);
};
SingletonLazy(const SingletonLazy &);
SingletonLazy & operator=(const SingletonLazy &);
};
SingletonLazy * SingletonLazy :: pgcls_singleton_instance = NULL;
std::mutex SingletonLazy ::singleton_mutex;
#endif
SingletonLazyV2Main.cpp
#include "SingletonLazyV2.h"
#include
#include
#include
#include
#include
void* thread_func(void *arg)
{
int i = 0;
while(i < 100)
{
SingletonLazy:: get_instance();
i++;
}
}
int main(void)
{
struct timeval start_time, end_time;
//运行计时开始
gettimeofday(&start_time, NULL);
int proc = 100;
pthread_t *threadId = (pthread_t *)malloc(proc*sizeof(pthread_t));
for (int i = 0; i < proc; i++)
{
pthread_create(&threadId[i], NULL, thread_func, NULL);
}
for (int i = 0; i < proc; i++)
{
pthread_join(threadId[i], NULL);
}
//运行计时结束
gettimeofday(&end_time, NULL);
//打印相关信息
printf("thread number = %d cost time msecond = %ld\n",proc,
(long)((end_time.tv_sec - start_time.tv_sec)*1000 + (end_time.tv_usec - start_time.tv_usec)/1000));
return 0;
}
编译并运行
root@wan:/wan/01singleton# g++ SingletonLazyV2Main.cpp -o SingletonLazyV2Main -lpthread -std=c++11
root@wan:/wan/01singleton# ./SingletonLazyV2Main
SingletonLazy 38 create Singleton Lazy
get_instance 20 new Singleton Lazy
get_instance 24 Singleton Lazy already
thread number = 100 cost time msecond = 1432
SingletonLazyV3.h
#ifndef SINGLETON_LAZY_H
#define SINGLETON_LAZY_H
#include
#include
class SingletonLazy
{
public:
/*
先判断下 if (NULL == pgcls_singleton_instance),如果条件不满足则直接返回,提高效率
采用双检查锁(DCL),即:double-checked locking
*/
static SingletonLazy * get_instance()
{
if(NULL == pgcls_singleton_instance)
{
singleton_mutex.lock();
if(NULL == pgcls_singleton_instance)
{
pgcls_singleton_instance = new SingletonLazy();
//printf("%s %d new Singleton Lazy\n",__FUNCTION__,__LINE__);
}
else
{
//printf("%s %d Singleton Lazy already \n",__FUNCTION__,__LINE__);
}
singleton_mutex.unlock();
}
else
{
//printf("%s %d Singleton Lazy already \n",__FUNCTION__,__LINE__);
}
return pgcls_singleton_instance;
}
private:
static std::mutex singleton_mutex;
// 静态的全局变量 声明为 私有 static 变量 防止外部进行访问
static SingletonLazy * pgcls_singleton_instance;
// 构造函数 析构函数 赋值 拷贝 函数 防止外部进行创建
SingletonLazy()
{
printf("%s %d create Singleton Lazy\n",__FUNCTION__,__LINE__);
};
~SingletonLazy()
{
printf("%s %d destroy Singleton Lazy\n",__FUNCTION__,__LINE__);
};
SingletonLazy(const SingletonLazy &);
SingletonLazy & operator=(const SingletonLazy &);
};
SingletonLazy * SingletonLazy :: pgcls_singleton_instance = NULL;
std::mutex SingletonLazy ::singleton_mutex;
#endif
SingletonLazyV3Main
#include "SingletonLazyV3.h"
#include
#include
#include
#include
#include
void* thread_func(void *arg)
{
int i = 0;
while(i < 100)
{
SingletonLazy:: get_instance();
i++;
}
}
int main(void)
{
struct timeval start_time, end_time;
//运行计时开始
gettimeofday(&start_time, NULL);
int proc = 10000;
pthread_t *threadId = (pthread_t *)malloc(proc*sizeof(pthread_t));
for (int i = 0; i < proc; i++)
{
pthread_create(&threadId[i], NULL, thread_func, NULL);
}
for (int i = 0; i < proc; i++)
{
pthread_join(threadId[i], NULL);
}
//运行计时结束
gettimeofday(&end_time, NULL);
//打印相关信息
printf("thread number = %d cost time msecond = %ld\n",proc,
(long)((end_time.tv_sec - start_time.tv_sec)*1000 + (end_time.tv_usec - start_time.tv_usec)/1000));
return 0;
}
编译并运行
root@wan:/wan/01singleton# g++ SingletonLazyV3Main.cpp -o SingletonLazyV3Main -lpthread -std=c++11
root@wan:/wan/01singleton# ./SingletonLazyV3Main
SingletonLazy 45 create Singleton Lazy
thread number = 10000 cost time msecond = 1210
SingletonLazyV4.h
#ifndef SINGLETON_LAZY_H
#define SINGLETON_LAZY_H
#include
#include
std::once_flag once_singleton;
class SingletonLazy
{
public:
static SingletonLazy * get_instance()
{
std::call_once(once_singleton,&SingletonLazy::_get_instance);
return pgcls_singleton_instance;
}
private:
static SingletonLazy * pgcls_singleton_instance;
static void _get_instance()
{
pgcls_singleton_instance = new SingletonLazy();
}
// 构造函数 析构函数 赋值 拷贝 函数 防止外部进行创建
SingletonLazy()
{
printf("%s %d create Singleton Lazy\n",__FUNCTION__,__LINE__);
};
~SingletonLazy()
{
printf("%s %d destroy Singleton Lazy\n",__FUNCTION__,__LINE__);
};
SingletonLazy(const SingletonLazy &);
SingletonLazy & operator=(const SingletonLazy &);
};
SingletonLazy * SingletonLazy :: pgcls_singleton_instance = NULL;
#endif
调用方式以及编译方法同上
SingletonLazyV5.h
#ifndef SINGLETON_LAZY_H
#define SINGLETON_LAZY_H
#include
#include
pthread_once_t once_singleton = PTHREAD_ONCE_INIT;
class SingletonLazy
{
public:
static SingletonLazy * get_instance()
{
pthread_once(&once_singleton,&SingletonLazy::_get_instance);
return pgcls_singleton_instance;
}
private:
static SingletonLazy * pgcls_singleton_instance;
static void _get_instance()
{
pgcls_singleton_instance = new SingletonLazy();
}
// 构造函数 析构函数 赋值 拷贝 函数 防止外部进行创建
SingletonLazy()
{
printf("%s %d create Singleton Lazy\n",__FUNCTION__,__LINE__);
};
~SingletonLazy()
{
printf("%s %d destroy Singleton Lazy\n",__FUNCTION__,__LINE__);
};
SingletonLazy(const SingletonLazy &);
SingletonLazy & operator=(const SingletonLazy &);
};
SingletonLazy * SingletonLazy :: pgcls_singleton_instance = NULL;
#endif
**针对 std::call_once 和pthread_once 单独进行讨论
写到这里单例模式介绍的基本差不多了,读者可以根据自己的情况进行调整,此外由于有篇幅有限,有关单例单例模式的扩展没有涉及到: