那家做网站好,wordpress广告赚钱,医院网站开发违法吗,wordpress 镜像1、单例设计模式 单例设计模式#xff0c;使用的频率比较高#xff0c;整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式#xff0c;同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉…1、单例设计模式 单例设计模式使用的频率比较高整个项目中某个特殊的类对象只能创建一个 并且该类只对外暴露一个public方法用来获得这个对象。 单例设计模式又分懒汉式和饿汉式同时对于懒汉式在多线程并发的情况下存在线程安全问题 饿汉式类加载的准备阶段就会将static变量、代码块进行实例化最后只暴露一个public方法获得实例对象。 懒汉式当需要用到的时候再去加载这个对象。这时多线程的情况下可能存在线程安全问题 对于饿汉式这里不做具体的解释本节只讨论多线程与懒汉式的线程安全问题
2、单线程下的懒汉模式
2.1、单例对象的创建 将类指针对象进行静态私有化并且在类外初始化这个对象为空静态能保证的是这个对象属于这个类不属于任何一个对象 私有化空构造器防止可以实例化对象 对外暴露一个public方法获取该对象如果在获取时发现该对象为空那么进行实例化否则直接返回 因此可以看到实例化只有一次多次获取到的对象的地址属于同一个 可以通过内部类的方式进行析构 首先在单例类内部进行私有化一个内部类对外暴露的public获取instance的对象接口在new实例化对象的时候创建一个内部类静态成员内部类静态成员的好处是只有一份当作用域结束时内部类就会负责析构掉主类的静态成员对象
class Single_Instance {
private:static Single_Instance *instance;Single_Instance() {}Single_Instance(const Single_Instance s){}class inner_class {public:~inner_class(){if(Single_Instance::instance){delete Single_Instance::instance;Single_Instance::instance NULL;std::cout inner_class::~inner_class(), 析构Single_Instance::instance对象 std::endl;}}};
public:static Single_Instance *get_Instance(){if(instance NULL){instance new Single_Instance();static inner_class innerClass;}return instance;}void func(){std::cout func(), instance instance std::endl;}
};
Single_Instance *Single_Instance::instance NULL;3、单例模式与多线程 单例模式的对象可能会被多个线程使用但是又必须保证这个单例的对象只有一份 不能重复创建、也必须保证这个对象在多线程使用过程中不会因为创建而产生数据安全问题即多线程抢占的创建这一个对象
class Single_Instance {
private:static Single_Instance *instance;Single_Instance() {}Single_Instance(const Single_Instance s){}class inner_class {public:~inner_class(){if(Single_Instance::instance){delete Single_Instance::instance;Single_Instance::instance NULL;std::cout inner_class::~inner_class(), 析构Single_Instance::instance对象 std::endl;}}};
public:static Single_Instance *get_Instance(){if(instance NULL){instance new Single_Instance();static inner_class innerClass;}return instance;}void func(){std::cout func(), instance instance std::endl;}
};
Single_Instance *Single_Instance::instance NULL;void thread_func()
{std::cout 子线程开始执行了 std::endl;Single_Instance *instance Single_Instance::get_Instance();std::cout thread_func, instance instance std::endl;std::cout 子线程执行结束了 std::endl;
}void test2()
{std::thread mythread1(thread_func);std::thread mythread2(thread_func);std::thread mythread3(thread_func);std::thread mythread4(thread_func);mythread1.join();mythread2.join();mythread3.join();mythread4.join();
}可以看到实例化不止一个单例对象这一现象违反了单例的思想因此需要在多线程抢占创建时进行互斥mutex
3.1、解决方案一
使用互斥量的方式对线程访问获取对象进行阻塞但是不难发现问题其实这个对象只创建一次之后的访问单纯的获取这个对象也要进行加锁逐个排队访问临界区这一现象导致效率极低
std::mutex mutex_lock;
static Single_Instance *get_Instance(){std::unique_lockstd::mutex uniqueLock(mutex_lock);if(instance NULL){instance new Single_Instance();static inner_class innerClass;}return instance;
}3.2、解决方式二
双重检查机制DCL进行绝对安全解决
双重检查 首先在锁外面加入一个if判断判断这个对象是否存在如果存在就没有必要上锁创建直接返回即可如果对象不存在首选进行加锁然后在if判断对象是否存在这个if的意义在于当多个线程阻塞在mutex锁头上时突然有一个线程1创建好了那么阻塞在mutex锁头上的线程2、3、4…都不用再继续创建因此在加一个if判断
这里还需要解释一下volatile关键字 volatile关键字的作用是防止cpu指令重排序重排序的意思就是干一件事123的顺序cpu可能重排序为132 为什么需要防止指令重排序因为对象的new过程分为三部曲 1分配内存空间、2执行构造方法初始化对象、3将这个对象指向这个空间 由于程序运行CPU会进行指令的重排序如果执行的指令是132顺序A线程执行完13之后并没有完成对象的初始化、而这时候转到B线程B线程认为对象已经实例化完毕、其实对象并没有完成初始化产生错误
static Single_Instance *get_Instance(){if(instance NULL){std::unique_lockstd::mutex uniqueLock(mutex_lock);if(instance NULL){instance new Single_Instance();static inner_class innerClass;}}return instance;
}3.3、解决方案三
但volatile关键字并不跨平台而在C11中提供了一种新的标准来解决这一问题并且跨平台可以通过atomic原子类来保证 将对象声明为原子类的指针std::atomic_thread_fence(std::memory_order_acquire)获取内存屏蔽的屏障关闭reorderstd::atomic_thread_fence(std::memory_order_release)将instance对象创建完毕之后进行解开内存屏障instance.store(tmp, std::memory_order_relaxed)将对象store到内存中。 Atomic类主要通过CAS锁来实现的具体点击这里
class Single_Instance {
private:std::atomicSingle_Instance* instance;Single_Instance() {}Single_Instance(const Single_Instance s){}
public:Single_Instance *get_Instance(){Single_Instance *tmp instance.load(std::memory_order_relaxed);std::atomic_thread_fence(std::memory_order_acquire);if(tmp NULL){std::unique_lockstd::mutex uniqueLock(mutex_lock);tmp instance.load(std::memory_order_relaxed);if(tmp NULL){tmp new Single_Instance();std::atomic_thread_fence(std::memory_order_release);instance.store(tmp, std::memory_order_relaxed);}}return tmp;}
};