#include<iostream>
#include<string>
#include<vector>
#include<mutex>
#include<thread>
using namespace std;
std::mutex resourece_mutex;
std::once_flag g_flag;//这是一个系统定义的标记
class mycas //这是一个单例类
{
static void CreateInstance() {//只被调用一次的函数
m_instance = new mycas();
static CGarhuishou cj;
}
private:
mycas() {}//私有化了构造函数
private:
static mycas* m_instance;
public:
static mycas* Getinstance()
{
提高效率
a)if(m_instance != nullptr)如果这个成立,则表示m_instance已经被new过了;
b)如果if(m_instance == nullptr)不代表m_instance一定没被new过
//if (m_instance == nullptr) {//双重锁定(双重检查)
// std::unique_lock<std::mutex> mymutex(resourece_mutex);//自动加锁
// if (m_instance == nullptr) {
// m_instance = new mycas();
// static CGarhuishou cj;
// }
//} //因为要写到call_once()所以将这一块代码注释掉
std::call_once(g_flag, CreateInstance);//两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕CreateInstance
//这里可以吧这个g_flag看成一个锁。
return m_instance;
}
class CGarhuishou {//类中套类,用来释放对象
public:
~CGarhuishou() {
if (mycas::m_instance) {
delete mycas::m_instance;
mycas::m_instance = nullptr;
}
}
};
void function() {
cout << "测试" << endl;
}
};
//类静态变量初始化
mycas* mycas::m_instance = nullptr;
//线程入口函数
void mythread() {
cout << "线程开始执行了" << endl;
mycas* pa = mycas::Getinstance();//这里可能有问题
cout << "线程执行完毕了" << endl;
}
int main()
{
/* (1)设计模式大概谈
* “设计模式”:代码的一些写法,(这些写法跟常规写法不太一样):程序灵活,维护起来可能方便,但是别人接管,阅读代码很痛苦
* 用设计模式写出来的代码是很晦涩的;《head first》
* 老外为了应付很大的项目时候,吧项目的开发经验、模块划分经验,总结整理成设计模式。(先有开发需求,后有理论总结和整理);
设计模式拿到中国来,不太一样,拿着一个程序(项目)往设计模式上套;一个小小的项目,它非要弄几个设计模式进去,本末倒置
设计模式肯定有它独特的优点,活学活用,不要生搬硬套;
* (2)单例设计模式
* 单例设计模式,使用的频率高,
* 单例:整个项目中,有某个或者某些特殊的类,属于该类的对象,我只能创建一个,多了我创建不了,
* 单例类;
* 注意:不能再析构函数中释放自身对象
* 因为析构一个对象,是需要调用这个对象的析构函数,如果在析构函数里面delete自身对象,那么delete中又要调用析构函数,陷入析构循环。
* (3)单例设计模式共享数据问题分析,解决
* 最好在主线程创建这个单例类,在其他线程创建之前就创建这个单例类,并且完成初始化,把该装载的数据装载,数据为只读
* 实际中面临的问题: 需要在我们自己创建的线程而不是主线程中来创建这个mycas这个单例类的对象,这种线程还不止一个
* 我们可能要面临Getinstance()这种成员函数要互斥;
* 问题1:可能第一个线程在执行m_instance = new mycas();的时候,第二个线程判断m_instance == nullptr,也会去new这个对象,这样就会出现问题
* 解决办法:加锁
* 问题2:在if上面直接加锁,只是为了第一次new这个对象而加个锁,这样在每次使用这个函数的时候都会进行加锁,效率大大降低
* 解决办法:双重检查。提高效率。只有在线程才开始的时候,多个线程进行判断,加锁,一旦一个加锁成功,创建对象成功,其他线程就直接返回就OK了,
* 下次再进行创建对象时候,也不用加锁,直接返回该对象就好了
* (3)std::call_once() C++引入的函数,该函数的第二个参数是一个函数名a();
* 功能:能够保证函数a只被调用一次。即便有许多线程,每个线程都调用了这个函数,只要用了这个函数,编译器就会保证这个函数a只被调用一次。
* 具备互斥量的能力,效率上,比互斥量消耗的资源更少;
* call_once()需要和一个标记结合使用,这个标记是std::once_flag;其实once_flag是一个结构
* call_once()通过这个标记来决定对应的函数()是否执行,调用call_once()成功后,call_once()就把这个标记设置为已调用状态
* 后续再次调用call_once()时候,只要这个标记为已调用状态,那么对应的函数a就不会再被执行。
*
*/
/*mycas m;
mycas m2;*///构造函数私有化了,不能通过这个方式生成类对象。
mycas* p_a = mycas::Getinstance();//创建一个对象,返回该类(mycas)对象的指针;
p_a->function();
//如下两个线程是同一个入口函数,但是要记住,这是两个线程,所以这里会有两个流程,或者两条通路同时执行mythread这个函数。同时执行getrinstance就可能出问题
std::thread mytobj1(mythread);
std::thread mytobj2(mythread);
const int aaa=10;
mytobj1.join();
mytobj2.join();
}