1.singleton模式的意图是什么?或者说使用singleton模式解决的问题是什么?
答:保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享!!!
2.解决上述问题的方法:
方法一: 全局变量或是静态变量
此方法存在的问题:这样做虽然能保证方便的访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建此类的局部实例。当然一不小心可能再创建另一个全局的实例。
方法二:
自己实现个简单的单例(C++版本)。
#ifndef SINGLETON_H
#define SINGLETON_H
#include<stddef.h>
#include<iostream>
#include<mutex>
using namespace std;
namespace test
{
std::mutex g_mutex;
template <typename T>
class Singleton
{
public:
static T* get()
{
if(m_instance_==NULL)
{
g_mutex.lock();
if(m_instance_==NULL)
{
m_instance_=new T();
}
g_mutex.unlock();
}
return m_instance_;
}
private:
Singleton(){}
static T* m_instance_;
};
template<typename T>
T* Singleton<T>::m_instance_=NULL;
}
#endif
上述代码有三个点需要说明下:
1.多线程:为防止多线程情况下产生多个单例指针,所以需要添加g_mutex来实现加锁和解锁。
2.double-check:就是
if(m_instance_==NULL)
做了两次判断,别的文章说如果不double-check会导致多个线程访问get函数时导致过多线程挂起,这句话我的体会不深,理解不深刻,鹦鹉学舌了!
3.
现在发现,这个单例模式没有释放类T的实例的操作!——
貌似智能指针auto_ptr能解决这个问题,或是添加Delete()函数,在某个适当的时候集中销毁!
4.还有构造函数声明为private能够防止在singleton外随意的实例化!
答:亦可以防止防止做为基类使用呀!和 5 的作用岂不是重复了?
5.还有将析构函数声明为private,这种设计我目前还不太理解是为什么?
答:应该是防止被做为基类使用!(2017.02.22)
6.在使用多线程测试此段代码时,使用g++做编译的命令格式是:
g++ -std=c++0x -Wl,--no-as-needed main.cpp -pthread -o test.out
main.cpp部分的代码如下:
#include"./Singleton.h"
#include<iostream>
#include<thread>
using namespace std;
class Me
{
public:
void Say()
{
std::cout<<"Hello Word"<<std::endl;
}
};
void hello()
{
while(true)
{
cout<<"he"<<endl;
}
}
int main()
{
thread first(&test::Singleton<Me>::get);
thread second(&test::Singleton<Me>::get);
thread third(&test::Singleton<Me>::get);
first.join();
second.join();
third.join();
return 0;
}
2017年2月27日更新以下内容:
无锁结构的实现方式,但是经试验验证,以现在代码的实现方式,耗时和有锁结构相比无明显区别:
这可能是因为获得锁之后的代码只需要瞬间的执行时间,从而没有明显因为等待锁而导致代码耗时增加!
#ifndef SINGLETON_H
#define SINGLETON_H
//template <typename T>
#include<stddef.h>
#include<iostream>
#include<mutex>
using namespace std;
namespace test
{
//std::mutex g_mutex;
template <typename T>
class Singleton
{
public:
static T* get()
{
if(0==__sync_val_compare_and_swap(&m_flag_,0,1))
{
//g_mutex.lock();
if(m_instance_==NULL)
{
//std::cout<<"get"<<std::endl;
m_instance_=new T();
std::cout<<"ptra:"<<m_instance_<<std::endl;
}
//g_mutex.unlock();
}
std::cout<<"already-1:"<<m_instance_<<std::endl;
return m_instance_;
}
private:
Singleton(){}
static int m_flag_;
static T* m_instance_;
};
template<typename T>
T* Singleton<T>::m_instance_=NULL;
template<typename T>
int Singleton<T>::m_flag_=0;
}
#endif
#include"./Singleton.h"
#include<iostream>
#include<thread>
#include<sys/time.h>
using namespace std;
class Me
{
public:
void Say()
{
std::cout<<"Hello Word"<<std::endl;
}
};
void hello()
{
while(true)
{
cout<<"he"<<endl;
}
}
#define N 10000
int main()
{
//Me* p[10]={NULL};
//Me* p=test::Singleton<Me>::get();
//p->Say();
//thread t(hello);
//t.join();
struct timeval start,end;
gettimeofday(&start,NULL);
thread pool[N];
for(int i=0;i<N;i++)
{
pool[i]=thread(&test::Singleton<Me>::get);
}
for(int i=0;i<N;i++)
{
pool[i].join();
}
gettimeofday(&end,NULL);
std::cout<<std::endl;
std::cout<<"total time:"<<double((end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec))<<std::endl;
return 0;
}