一:设计模式
“设计模式”:代码的一些写法(这些写法跟常规写法不怎么一样):程序灵活,维护方便,但是别人接管、阅读代码很痛苦
用“设计模式”理念写出来的代码很晦涩
老外把项目的开发经验、模块划分经验,总结整理成 设计模式(先有开发需求,后有理论总结和整理)
国内不太一样,拿着一个程序(项目)往设计模式上套;一个小小的项目,非要弄几个设计模式进去,本末倒置
设计模式有它独特的有点,要活学活用,不要深陷其中,生搬硬套
二.单例设计模式
单例设计模式使用的频率比较高;
单例:整个项目中,有某个或某些特殊的类,只能创建一个对象
单例模式演示(使用delete小技巧):
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
//单例类定义:
class MySingleton
{
private:
MySingleton() {} //私有化构造函数
private:
static MySingleton* m_instance; //静态成员函数
public:
static MySingleton* GetInstance()
{
if (m_instance == NULL)
{
m_instance = new MySingleton();
static DeleteSingleton DS;
}
return m_instance;
}
//delete技巧
class DeleteSingleton //类中套类,用来释放MySingleton
{
public:
~DeleteSingleton()//析构函数
{
if (MySingleton::m_instance)
{
delete MySingleton::m_instance;
MySingleton::m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类外静态变量初始化
MySingleton* MySingleton::m_instance = NULL;
int main()
{
MySingleton* p_s = MySingleton::GetInstance();
//创建一个对象,返回指向该类(MySingleton)对象的指针
//MySingleton* p_s1 = MySingleton::GetInstance(); //其实p_s1与p_s是指向同一个对象的指针
//MySingleton p_s2;
//报错,构造函数权限为private,不能创建对象,只能通过GetInstance()创建对象
p_s->func();
MySingleton::GetInstance()->func(); //静态成员函数不需要实例化对象也能访问
return 0;
}
三.单例模式共享数据问题分析、解决
尽可能在创建线程之前在主线程中实例化单例类,并完成数据装载等,确保在多线程中数据为只读,这样就不需要互斥量优化多线程
但是面临的问题是:有时候需要在我们自己创建的线程(而不是主线程)中来创建单例类的对象,这种线程不止一个
我们可能会面临GetInstance()这种成员函数要互斥,因为可能多个线程同时创建单例类对象
下面的线程入口函数中需要创建单例类对象,可以使用互斥量来解决此类问题
std::mutex resource_mutex; //定义互斥锁,防止创建多个单例类对象
//单例类定义:
class MySingleton
{
private:
MySingleton() {} //私有化构造函数
private:
static MySingleton* m_instance; //静态成员函数
public:
static MySingleton* GetInstance()
{
std::unique_lock<std::mutex> myMutex(resource_mutex);//自动加锁(lock())
if (m_instance == NULL)
{
//不加锁的情况下如果一个线程执行到这里,切换到另一个线程执行,则两个线程都会创建对象
m_instance = new MySingleton();
static DeleteSingleton DS;
}
return m_instance;
}
//delete技巧
class DeleteSingleton //类中套类,用来释放MySingleton
{
public:
~DeleteSingleton()//析构函数
{
if (MySingleton::m_instance)
{
delete MySingleton::m_instance;
MySingleton::m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类外静态变量初始化
MySingleton* MySingleton::m_instance = NULL;
//线程入口函数
void mythread()
{
cout << "我的线程开始执行..." << endl;
MySingleton* p_s = MySingleton::GetInstance(); //有问题
cout << "我的线程执行完毕..." << endl;
}
int main()
{
std::thread myThread1(mythread);
std::thread myThread2(mythread);
//这两个线程是同一个入口函数,所以这里会有两个流程同时开始执行mythread函数
myThread1.join();
myThread2.join();
return 0;
}
上面的程序有个问题,如果该函数GetInstance()调用次数较多,则每次调用该函数都要加锁,但其实只要我们创建了一个单例类的对象后,以后的操作就为读,并不需要互斥量来保护,所以该方法是低效的。
解决:采用双重检查的方法,代码如下(修改了GetInstance()函数的实现,main函数不变),即在外层多加一次判断,只有第一次条件成立才会进入并加锁,后续调用GetInstance()函数时,不会加锁,提高效率。
std::mutex resource_mutex; //定义互斥锁,防止创建多个单例类对象
//单例类定义:
class MySingleton
{
private:
MySingleton() {} //私有化构造函数
private:
static MySingleton* m_instance; //静态成员函数
public:
static MySingleton* GetInstance()
{
//a)if(m_instance!=NULL)条件成立,则m_instance已经被new过了
//b)if(m_instance==NULL)条件成立,不代表m_instance一定没被new过,
//也就是不加锁的情况下可能发生两个线程同时创建单例类的对象
if (m_instance) //双重锁定(双重检查),可以提高效率(只有第一次条件成立才会进入并加锁)
{
std::unique_lock<std::mutex> myMutex(resource_mutex);//自动加锁(lock())
if (m_instance == NULL)
{
//不加锁的情况下如果一个线程执行到这里,切换到另一个线程执行,则两个线程都会创建对象
m_instance = new MySingleton();
static DeleteSingleton DS;
}
}
return m_instance;
}
//delete技巧
class DeleteSingleton //类中套类,用来释放MySingleton
{
public:
~DeleteSingleton()//析构函数
{
if (MySingleton::m_instance)
{
delete MySingleton::m_instance;
MySingleton::m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类外静态变量初始化
MySingleton* MySingleton::m_instance = NULL;
//线程入口函数
void mythread()
{
cout << "我的线程开始执行..." << endl;
MySingleton* p_s = MySingleton::GetInstance(); //有问题
cout << "我的线程执行完毕..." << endl;
}
四.std::call_once(),c++11引入的函数
函数模板,第二个参数是一个函数名Function
功能:保证函数Function()只被调用一次
call_once具备互斥量能力,效率上比互斥量消耗的资源更少
call_once()需要与一个标记结合使用,这个标记std::once_flag是一个结构;
call_once(通过这个标记来决定对应的函数Function()是否执行,调用call_once()成功后,call_once()就把这个标记设置为一种已调用状态
后续再次调用call_once(),只要once_flag被设置为了“已调用”状态,那么对应的函数Function()就不会再被调用了
下面为修改后的单例类程序,添加了一个CreateInstanceOnce()函数。
std::mutex resource_mutex; //定义互斥锁,防止创建多个单例类对象
std::once_flag myOnceFlag; //这是个系统定义的标记
//单例类定义:
class MySingleton
{
static void CreateInstanceOnce() //只被调用一次
{
cout << "CreateInstanceOnce()被执行" << endl;
m_instance = new MySingleton();
static DeleteSingleton DS;
}
private:
MySingleton() {} //私有化构造函数
private:
static MySingleton* m_instance; //静态成员函数
public:
static MySingleton* GetInstance()
{
//假设两个线程同时执行到这里,其中一个线程要等另一个线程执行完CreateInstanceOnce
std::call_once(myOnceFlag, CreateInstanceOnce);
cout << "call_once()执行完毕" << endl;
return m_instance;
}
//delete技巧
class DeleteSingleton //类中套类,用来释放MySingleton
{
public:
~DeleteSingleton()//析构函数
{
if (MySingleton::m_instance)
{
delete MySingleton::m_instance;
MySingleton::m_instance = NULL;
}
}
};
void func()
{
cout << "测试" << endl;
}
};
//类外静态变量初始化
MySingleton* MySingleton::m_instance = NULL;
//线程入口函数
void mythread()
{
cout << "我的线程开始执行..." << endl;
MySingleton* p_s = MySingleton::GetInstance(); //有问题
cout << "我的线程执行完毕..." << endl;
}
执行结果如下图所示,可以看出CreateInstanceOnce()只被执行了一次。
网友评论