单例设计模式共享数据分析、解决、call_once
一 设计模式大概谈
二 单例设计模式
该类只能创建一个对象
#include <stdio.h>
#include <iostream>
using namespace std;
class MyCAS
{
private:
MyCAS(){}
static MyCAS* m_instance;
public:
static MyCAS* GetInstance()
{
if(m_instance == NULL)
{
m_instance = new MyCAS();
//释放m_instance
static CGarhuishou cl;
}
return m_instance;
}
class CGarhuishou
{
public:
//类的析构函数
~CGarhuishou()
{
if(MyCAS::m_instance)
{
delete MyCAS::m_instance;
MyCAS::m_instance = NULL;
}
}
};
void func()
{
cout<<"test"<<endl;
}
};
//静态成员 类外初始化
MyCAS *MyCAS::m_instance = NULL;
int main(void)
{
MyCAS *p_a = MyCAS::GetInstance(); //创建一个对象,返回该类对象的指针 而且只能创建一个
MyCAS *p_b = MyCAS::GetInstance(); //返回唯一对象
cout<<endl;
return 0;
}
三 单例设计模式共享数据问题分析、解决
问题:需要在我们自己创建的线程(而不是主线程)中创建MyCAS,这个单例类的对象,这种线程可能不止一个(最少两个)。我们可能要面临GetInstance要互斥。
#include <stdio.h>
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
std::mutex resource_mutex;
class MyCAS
{
private:
MyCAS(){}
static MyCAS* m_instance;
public:
static MyCAS* GetInstance()
{
//提高效率。
//如果if(m_ instance=NULL)条件成立,则肯定表示m_ instance已经被new过了
//b)如果if( m instance=NULL),不代表 m instance-定没被new过;
if(m_instance == NULL) //双重锁定 双重检查
{
std::unique_lock<std::mutex>mymutex(resource_mutex);//自动加锁
{
m_instance = new MyCAS();
//释放m_instance
static CGarhuishou cl;
}
}
return m_instance;
}
class CGarhuishou
{
public:
//类的析构函数
~CGarhuishou()
{
if(MyCAS::m_instance)
{
delete MyCAS::m_instance;
MyCAS::m_instance = NULL;
}
}
};
void func()
{
cout<<"test"<<endl;
}
};
//静态成员 类外初始化
MyCAS *MyCAS::m_instance = NULL;
//线程入口
void mythread()
{
cout<<"my thread start"<<endl;
MyCAS *p_a = MyCAS::GetInstance(); //这里可能出现问题 两个线程同时进入getInstance
COUT<<"my thread over"<<endl;
return;
}
int main(void)
{
// MyCAS *p_a = MyCAS::GetInstance(); //创建一个对象,返回该类对象的指针 而且只能创建一个
// p_a->func();
// cout<<endl;
std::thread myobj(mythread);
std::thread myobj1(mythread);
//这两个线程虽然是同一个入口函数,但是由于是两个线程,所以这里会出现两条通路同时执行getinstance
//会到此m_instance被new多次
return 0;
}
四 std::call_once()
该函数的第二个参数是一个函数名a(),call_once功能保证a函数被调用一次。
具备互斥量的能力,而且效率比互斥量消耗的资源更少
call_once需要与一个标记结合使用,这个标记std::once_flag,该标记其实是一个结构
call_once就是通过这个标记来决定对应的函数a是否执行,调用call_once成功后,call_once就把这个标志置位已调用状态。a函数不会再执行。
#include <stdio.h>
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
std::mutex resource_mutex;
std::once_flag g_flag;
class MyCAS
{
public:
static void CreateInstance() //只被调用一次
{
std::chrono::milliseconds dura(20000);//休息20s
std::this_thread::sleep_for(dura);
cout<<"CreateInstance creating"<<endl;
m_instance = new MyCAS();
//释放m_instance
static CGarhuishou cl;
}
private:
MyCAS(){}
static MyCAS* m_instance;
public:
static MyCAS* GetInstance()
{
// //提高效率。
// //如果if(m_ instance=NULL)条件成立,则肯定表示m_ instance已经被new过了
// //b)如果if( m instance=NULL),不代表 m instance-定没被new过;
// if(m_instance == NULL) //双重锁定 双重检查
// {
// std::unique_lock<std::mutex>mymutex(resource_mutex);//自动加锁
// {
// m_instance = new MyCAS();
// //释放m_instance
// static CGarhuishou cl;
// }
// }
std::call_once(g_flag,CreateInstance); //两个线程同时执行到这个,则只能有一个被执行,且被卡住。
cout<<"call_once over"<<endl;
return m_instance;
}
class CGarhuishou
{
public:
//类的析构函数
~CGarhuishou()
{
if(MyCAS::m_instance)
{
delete MyCAS::m_instance;
MyCAS::m_instance = NULL;
}
}
};
void func()
{
cout<<"test"<<endl;
}
};
//静态成员 类外初始化
MyCAS *MyCAS::m_instance = NULL;
//线程入口
void mythread()
{
cout<<"my thread start"<<endl;
MyCAS *p_a = MyCAS::GetInstance(); //这里可能出现问题 两个线程同时进入getInstance
cout<<"my thread over"<<endl;
return;
}
int main(void)
{
// MyCAS *p_a = MyCAS::GetInstance(); //创建一个对象,返回该类对象的指针 而且只能创建一个
// p_a->func();
// cout<<endl;
std::thread myobj(mythread);
std::thread myobj1(mythread);
//这两个线程虽然是同一个入口函数,但是由于是两个线程,所以这里会出现两条通路同时执行getinstance
//会到此m_instance被new多次
return 0;
}
CreateInstance creating只被打印一次