一:设计模式大概谈
“设计模式”:代码的一些写法(这些写法跟常规的写法不怎么一样):程序灵活,维护起来可能方便,但是别人接管、阅读代码都会很痛苦;
用“设计模式”理念写出来的代码很晦涩的;《head first》
【c++学习|17.7 单例设计模式共享数据分析、解决与call_once】二:单例设计模式
单例设计模式,使用频率比较高。
单例:在整个项目中,有某个或者某些特殊的类,属于该类的对象,我只能创建1个,多了我创建不了。
单例类;
class MyCAS//这是一个单例类
{
private:
MyCAS() {}//私有化构造函数
~MyCAS() {}private:
static MyCAS* m_instance;
//静态成员变量public:
static MyCAS* GetInstance()
{
if (m_instance == NULL)
{
m_instance = new MyCAS();
static CGarhuishou cl;
}
return m_instance;
} class CGarhuishou//类中套类,用来释放对象
{
public:
~CGarhuishou()//类的析构函数中
{
if (MyCAS::m_instance)
{
delete m_instance;
m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;
int main()
{
MyCAS* p_a = MyCAS::GetInstance();
//创建一个对象,返回该类(MyCAS)对象的指针;
p_a->func();
MyCAS::GetInstance()->func();
//该装载的数据装载
return 0;
}
三:单例设计模式共享数据问题分析、解决
面临的问题:需要在我们自己创建的线程(而不是主线程)中创建MyCAS这个单例类的对象,这种线程可能不止一个(最少2个)。
我们可能会面临GetInstance这种成员函数要互斥;
虽然这两个线程是同一个入口函数,但大家千万要记住,这是两个线程,所以这里会有两个流程(两条通路)同时开始执行 mythread 这个函数。
std::mutex resource_mutex;
std::once_flag g_flag;
//这是个系统定义的标记class MyCAS//这是一个单例类
{
private:
MyCAS() {}//私有化构造函数
~MyCAS() {}private:
static MyCAS* m_instance;
//静态成员变量public:
static MyCAS* GetInstance()
{
// 提高效率
// a)if (m_instance != NULL)条件成立,则肯定表示m_instance已经被new过;
// b)if (m_instance == NULL)条件成立,不代表m_instance一定没被new过;
if (m_instance == NULL)//双重检查(双重锁定)如果条件不成立,则肯定表示m_instance已经被new过了。
{
std::unique_lock mymutex(resource_mutex);
//自动加锁
if (m_instance == NULL)
{
m_instance = new MyCAS();
static CGarhuishou cl;
}
}
return m_instance;
} class CGarhuishou//类中套类,用来释放对象
{
public:
~CGarhuishou()//类的析构函数中
{
if (MyCAS::m_instance)
{
delete m_instance;
m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;
//线程入口函数
void mythread()
{
cout << "我的线程开始执行了" << endl;
MyCAS* p_a = MyCAS::GetInstance();
//这里可能就有问题了
cout << "我的线程执行完毕了" << endl;
return;
}int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
t1.join();
t2.join();
return 0;
}
四:std::call_once(函数模板)
C++11引入的函数,该函数的第二个参数是一个函数名a();
call_once功能能够保证函数a()只被调用一次;
call_once具备互斥量这种能力,而且效率上,比互斥量消耗的资源更少。
call_once需要与一个标记结合使用,这个标记std::once_flag;其实std::once_flag是一个结构。
call_once就是通过这个标记来决定对应的函数a()是否执行,调用这个call_once成功后,就把这个标记设置为一种已调用状态;后续再次调用call_once,只要这个once_flag被设置为“已调用”状态,那么对应的函数a()就不会再执行了。
std::mutex resource_mutex;
std::once_flag g_flag;
//这是个系统定义的标记class MyCAS//这是一个单例类
{
static void CreateInstance()//只被调用1次
{
std::chrono::milliseconds dura(2000);
//休息2秒
std::this_thread::sleep_for(dura);
cout << "CreateInstance()只执行了一次" << endl;
m_instance = new MyCAS();
static CGarhuishou cl;
}private:
MyCAS() {}//私有化构造函数
~MyCAS() {}private:
static MyCAS* m_instance;
//静态成员变量public:
static MyCAS* GetInstance()
{
std::call_once(g_flag, CreateInstance);
//两个线程同时执行到这里,其中一个线程等待另外一个线程执行完毕
cout << "std::call_once()执行完毕" << endl;
return m_instance;
} class CGarhuishou//类中套类,用来释放对象
{
public:
~CGarhuishou()//类的析构函数中
{
if (MyCAS::m_instance)
{
delete m_instance;
m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;
//线程入口函数
void mythread()
{
cout << "我的线程开始执行了" << endl;
MyCAS* p_a = MyCAS::GetInstance();
//这里可能就有问题了
cout << "我的线程执行完毕了" << endl;
return;
}int main()
{
std::thread t1(mythread);
std::thread t2(mythread);
t1.join();
t2.join();
return 0;
}
推荐阅读
- c++学习|17.8 condition_variable、wait、notify_one与notify_all
- c++学习|17.6 unique_lock详解
- c++学习|14.4 类内初始化、默认构造函数、“=default”和“=delete”
- C++|C++ - 智能指针
- C++|C++ - Lambda表达式
- C++ - 子类与父类的同名成员变量
- C++|【C++】多态
- QT|QT---创建对话框3(形状可变对话框的实现)
- QT|Qt状态机的使用