当前位置: 首页 > news >正文

北京学网站开发铜陵58同城做网站

北京学网站开发,铜陵58同城做网站,高端网站建设网站,自己做第一个网站十三、day13 今天学习如何单例模式实现逻辑层的设计。内容包括服务器如何能捕获信号使其安全退出、单例模标类 1. 什么是单例模式#xff1f; 单例模式#xff08;Singleton#xff09;#xff0c;保证一个类仅有一个实例#xff0c;并提供一个访问它的全局访问点…十三、day13 今天学习如何单例模式实现逻辑层的设计。内容包括服务器如何能捕获信号使其安全退出、单例模标类 1. 什么是单例模式 单例模式Singleton保证一个类仅有一个实例并提供一个访问它的全局访问点单例模式是在内存中仅会创建一次对象的设计模式。 //通过静态成员变量实现单例 //懒汉式 class Single2 { private:Single2() {}Single2(const Single2 ) delete;Single2 operator(const Single2) delete; public:static Single2 GetInst(){static Single2 single;return single;} }; 在上面的代码块中定义了一个Single2类Single2类的默认构造函数被声明为私有且删除拷贝构造函数和赋值运算符确保Single2类不能通过拷贝创建或赋值创建新的实例。 Single2类只有一个公共静态方法GetInst()用于获取Single2类的唯一实例。 局部静态成员single用于存储Single2类的唯一实例通过返回single即可返回该实例。 单例模式的简单实现可总结为 构造方法是私有的 对外暴露的获取访问是公有的静态的 唯一实例的存储方式是静态的 风险上述代码块懒汉式生成了唯一实例但在多线程方式下生成的实例可能会存在多个如果多个线程同时调用GetInst()时都会去实例化一个simgle对象使得Single2类被重复实例化 1单例模式的分类 饿汉式类加载就会导致该单实例对象被创建 懒汉式类加载不会导致该单实例对象被创建而是首次使用该对象时被创建 懒汉式创建对象的方法是函数中创建静态局部变量这样只有在对象第一次被使用时才会创建实例而饿汉式一般已经在类中提前声明了静态变量single这样在类加载时便已经提前创建好实例。 上述代码块的单例模式就是通过懒汉式实现的静态变量single在第一次使用Single2类的GetInst()时被创建其声明周期随着进程结束而结束。 饿汉式单例模式实现 //饿汉式 class Single2Hungry { private:Single2Hungry() { }Single2Hungry(const Single2Hungry) delete;Single2Hungry operator(const Single2Hungry) delete; public:static Single2Hungry* GetInst(){if (single nullptr)single new Single2Hungry();return single;} private:static Single2Hungry* single; }; 饿汉模式在类加载时已经创建好该对象在程序调用时直接返回该单例对象即可可以避免线程安全问题。 多线程和单线程下进行测试 //饿汉式初始化 Single2Hungry* Single2Hungry::single Single2Hungry::GetInst(); void thread_func_s2(int i) {cout this is thread i endl;cout inst is Single2Hungry::GetInst() endl; } void test_single2hungry() {cout s1 addr is Single2Hungry::GetInst() endl;cout s2 addr is Single2Hungry::GetInst() endl;for (int i 0; i 3; i){thread tid(thread_func_s2, i);tid.join();} } int main(){test_single2hungry() } 输出为 s1 addr is 0x1e4b00 s2 addr is 0x1e4b00 this is thread 0 inst is 0x1e4b00 this is thread 1 inst is 0x1e4b00 this is thread 2 inst is 0x1e4b00 可见无论单线程还是多线程模式下通过静态成员变量的指针实现的单例类都是唯一的。饿汉式是在程序启动时就进行单例的初始化这种方式也可以通过懒汉式调用无论饿汉式还是懒汉式都存在一个问题就是什么时候释放内存多线程情况下释放内存就很难了还有二次释放内存的风险。 2懒汉式的改进 上面提到了懒汉式有一定的风险在多线程下可能会创建多个Single2的实例如果多个线程同时调用GetInst()时都会去实例化一个simgle对象使得Single2类被重复实例化。 通过对GetInst()方法枷锁或者对Single2类进行加锁可以解决该风险每个线程在进入方法前都要等到别的线程都离开此方法不会有两个线程同时进入此方法。 //懒汉式指针 //即使创建指针类型也存在问题 class SinglePointer { private:SinglePointer() { }SinglePointer(const SinglePointer) delete;SinglePointer operator(const SinglePointer) delete; public:static SinglePointer *GetInst(){if (single ! nullptr){return single;}s_mutex.lock();if (single ! nullptr){s_mutex.unlock();return single;}single new SinglePointer();s_mutex.unlock();return single;} private:static SinglePointer *single;static mutex s_mutex; }; 该段代码块通过双重检验枷锁进行加锁避免了直接加锁造成的问题每次去获取对象都需要先获取锁并发性能非常地差。 双重检验枷锁 如果已经实例化了则不需要加锁直接返回实例化对象 如果没有实例化对象则加锁然后再判断一次有没有实例化 如果实例化了就解锁并返回实例化对象 如果没有实例化就初始化实例化对象并解锁返回实例化对象 进行测试 //懒汉式 //在类的cpp文件定义static变量 SinglePointer *SinglePointer::single nullptr; std::mutex SinglePointer::s_mutex;void thread_func_lazy(int i) {cout this is lazy thread i endl;cout inst is SinglePointer::GetInst() endl; } void test_singlelazy() {for (int i 0; i 3; i){thread tid(thread_func_lazy, i);tid.join();}//何时释放new的对象造成内存泄漏 } int main(){test_singlelazy(); } 输出为 this is lazy thread 0 inst is 0xbc1700 this is lazy thread 1 inst is 0xbc1700 this is lazy thread 2 inst is 0xbc1700 尽管多线程下懒汉式可能会创建多个Single2类实例的问题被解决但无论懒汉式还是饿汉式都有一个共同的问题需要解决什么时候释放内存多线程下多次delete也会造成崩溃。 3智能指针方法 使用智能指针方法自动回收内存的机制设计单例类 //利用智能指针解决释放问题 class SingleAuto { private:SingleAuto() { }SingleAuto(const SingleAuto) delete;SingleAuto operator(const SingleAuto) delete; public:~SingleAuto(){cout single auto delete success endl;}static std::shared_ptrSingleAuto GetInst() {if (single ! nullptr) {return single;}s_mutex.lock();if (single ! nullptr) {s_mutex.unlock();return single;}single std::make_sharedSingleAuto();s_mutex.unlock();return single;} private:static std::shared_ptrSingleAuto single;static mutex s_mutex; }; SingleAuto类的GetInst()返回std::shared_ptrSingleAuto类型的变量single。因为single是静态成员变量所以会在进程结束时被回收。智能指针被回收时会调用内置指针类型的析构函数从而完成内存的回收。 测试 // 智能指针方式 std::shared_ptrSingleAuto SingleAuto::single nullptr; mutex SingleAuto::s_mutex; void test_singleauto() {auto sp1 SingleAuto::GetInst();auto sp2 SingleAuto::GetInst();cout sp1 is sp1 endl;cout sp2 is sp2 endl;//此时存在隐患可以手动删除裸指针造成崩溃// delete sp1.~SingleAuto(); } int main(){test_singleauto(); } 输出 sp1 is 0x1174f30 sp2 is 0x1174f30 智能指针方式不存在内存泄漏但是有一个隐患单例类的析构函数是公有成员如果被人手动调用会存在崩溃问题比如将上边测试中的注释打开程序会崩溃 4辅助类智能指针单例模式 将析构函数私有化在构造智能指针时指定删除器通过传递一个辅助类或者辅助函数帮助智能指针回收内存时调用指定的析构函数。因为析构函数私有化以后智能指针在引用计数归零后无法调用对象的析构函数进行销毁。所以必须指定一个删除器该删除器是单例类的友元类可以访问单例类的私有或公有成员可以通过删除器间接调用单例类的析构函数。 // safe deletor //该类定义仿函数调用SingleAutoSafe析构函数 class SingleAutoSafe;class SafeDeletor { public:void operator()(SingleAutoSafe *sf){cout this is safe deleter operator() endl;delete sf;} };class SingleAutoSafe { private:SingleAutoSafe() {}~SingleAutoSafe(){cout this is single auto safe deletor endl;}SingleAutoSafe(const SingleAutoSafe ) delete;SingleAutoSafe operator(const SingleAutoSafe ) delete;//定义友元类通过友元类调用该类析构函数friend class SafeDeletor; public:static std::shared_ptrSingleAutoSafe GetInst(){if (single ! nullptr){return single;}s_mutex.lock();if (single ! nullptr){s_mutex.unlock();return single;}//额外指定删除器single std::shared_ptrSingleAutoSafe(new SingleAutoSafe, SafeDeletor());//也可以指定删除函数// single std::shared_ptrSingleAutoSafe(new SingleAutoSafe, SafeDelFunc);s_mutex.unlock();return single;} private:static std::shared_ptrSingleAutoSafe single;static mutex s_mutex; }; 如果是提前声明SafeDeletor 而先定义SingleAutoSafe会造成 incomplete type类型不完整的错误因为被提前声明的类可以在后面定义但在声明类前面定义的其他类中使用声明类时只能使用声明类的指针而不能创建声明类的实例。 SafeDeletor类中重载了()实现类模拟函数的作用。 SafeDeletor要写在SingleAutoSafe上边并且SafeDeletor要声明为SingleAutoSafe类的友元类这样就可以访问SingleAutoSafe的析构函数了。在构造single时制定了SafeDeletor()single在回收时会调用仿函数SafeDeletor()从而完成内存的销毁。同时SingleAutoSafe的析构函数为私有无法被外界显式调用。 5通用的单例模板类 通过声明单例的模板类然后继承这个单例模板类的所有类就是单例类了可以达到泛型编程提高效率的目的 template typename T class Single_T { protected:Single_T() default;Single_T(const Single_TT st) delete;Single_T operator(const Single_TT st) delete;~Single_T(){cout this is auto safe template destruct endl;} public:static std::shared_ptrT GetInst(){if (single ! nullptr){return single;}s_mutex.lock();if (single ! nullptr){s_mutex.unlock();return single;}//额外指定删除器single std::shared_ptrT(new T, SafeDeletor_TT());//也可以指定删除函数// single std::shared_ptrSingleAutoSafe(new SingleAutoSafe, SafeDelFunc);s_mutex.unlock();return single;} private:static std::shared_ptrT single;static mutex s_mutex; };//模板类的static成员要放在h文件里初始化 template typename T std::shared_ptrT Single_TT::single nullptr; template typename T mutex Single_TT::s_mutex; 模板类的静态成员变量要在头文件中初始化而非模板类的静态成员变量一般在cpp文件中初始化。 应用定义一个网络的单例类继承上述模板类并将构造和析构设置为私有同时设置友元保证自己的析构和构造可以被友元类调用. class SingleNet : public Single_TSingleNet { private:SingleNet() default;SingleNet(const SingleNet ) delete;SingleNet operator(const SingleNet ) delete;~SingleNet() default;friend class SafeDeletor_TSingleNet;friend class Single_TSingleNet; }; 删除器SafeDeletor_T和单例模板类Single_T都是模板需要提前定义。 测试 void test_singlenet() {auto sp1 SingleNet::GetInst();auto sp2 SingleNet::GetInst();cout sp1 is sp1 endl;cout sp2 is sp2 endl; } 5总结 1. 为什么要有单例模式 使用单例模式的原因 资源控制单例模式可以用来控制系统中的资源例如数据库连接池或线程池确保这些关键资源不会被过度使用。 内存节省当需要一个对象进行全局访问但创建多个实例会造成资源浪费时单例模式可以确保只创建一个实例节省内存。 共享单例模式允许状态或配置信息在系统的不同部分之间共享而不需要传递实例。 延迟初始化单例模式支持延迟初始化即实例在首次使用时才创建而不是在类加载时。 一致的接口单例模式为客户端提供了一个统一的接口来获取类的实例使得客户端代码更简洁。 易于维护单例模式使得代码更易于维护因为所有的实例都使用相同的实例便于跟踪和修改变更。 单例模式的应用场景 配置管理器在应用程序中配置信息通常只需要读取一次并全局使用。单例模式用于确保配置管理器只被实例化一次。 日志记录器一个系统中通常只需要一个日志记录器来记录所有的日志信息使用单例模式可以避免日志文件的重复写入。 数据库连接池数据库连接是一种有限的资源使用单例模式可以确保数据库连接池的唯一性并且能够重用连接减少连接创建和销毁的开销。 线程池类似于数据库连接池线程池也是有限的资源使用单例模式可以避免创建过多的线程提高应用程序的并发性能。 任务调度器在需要全局调度和管理的场景下如定时任务调度器单例模式提供了一个集中的管理方式。 网站的计数器一般也是采用单例模式实现否则难以同步。 2. 单例模式中GetInst()为什么是静态的 1静态方法可以通过类名直接访问无需创建类的实例。这样可以方便地获取唯一实例而不需要先实例化类。 2类的构造函数已经被私有化无法直接实例化对象智能通过定义静态成员函数的方式通过类名::方法名的方式进行构造访问 3静态局部变量的方式是线程安全的能确保在多线程环境下也只会创建一个实例
http://www.w-s-a.com/news/755121/

相关文章:

  • icp网站备案流程wordpress post 405
  • 网站怎样上传到空间重庆有多少网站
  • 用模板建商城购物网站嘉定专业网站建设
  • 网站开发与应用 论文dede手机医院网站模板
  • 织梦 网站栏目管理 很慢自学网页设计难吗
  • 茶文化建设网站的意义平顶山网站建设服务公司
  • 建设网站详细流程南京宣传片制作公司
  • 合肥网站排名什么网站做电气自动化兼职
  • 如何用api做网站交通建设门户网站
  • 阳西住房和城乡规划建设局网站长沙网站seo技巧
  • 长沙知名网站推广手机画设计图软件
  • 顺德公司做网站自己有网站怎么优化
  • 南京网站开发南京乐识专业外贸流程知乎
  • 盐田区住房和建设局网站分类网站有哪些
  • 建一个团购网站WordPress文章字号设置
  • 做漂亮的网站东营网站seo
  • 网站开发摊销做设计哪个网站可以接单
  • 惠州h5网站建设建设公司网站报价
  • 做网站多少钱 优帮云嘉兴五县两区网站建设
  • 三亚旅游网站策划书企业网站建设的定位
  • 网站建设工作台账网站建设的实验结论
  • 商业网站建设平台制作软件的软件
  • 本地网站开发wordpress页面关键词和描述
  • 微网站 合同软件开发培训方案
  • 怎么做淘宝客网站备案广告公司图片大全
  • 微信小程序展示网站建设多少钱做网站用什么软件初二
  • 瀑布流资源网站模板打码网站建设
  • wordpress 支付宝打赏网站视觉优化的意义
  • 建设网站需要几个文件夹永久免费内存大服务器
  • 可信赖的手机网站建设wordpress 显示摘要