七、单例设计模式
1、单例类的设计
在众多的设计模式中,单例设计模式使用的频率比较高,这里做一个总结。所谓单例:是整个项目中,有某个或者某些特殊的类,只能创建一个该类的对象。这个类可以通过特殊的写法构建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include "pch.h" #include <iostream> class MyCAS // 这是一个单例类 { private: MyCAS() {} private: static MyCAS* my_instance; public: static MyCAS* GetInstance() { if (NULL == my_instance) { my_instance = new MyCAS(); static GarbageCollection garcolle; } return my_instance; }
void Test() { std::cout << "Hello MyCAS " <<this<< std::endl; }
class GarbageCollection // garbage collection,设计的很巧妙 { public: ~GarbageCollection() { if (MyCAS::my_instance) { delete MyCAS::my_instance; MyCAS::my_instance = NULL; } }
}; };
MyCAS* MyCAS::my_instance = NULL; int main() { MyCAS* mycas_ptr = MyCAS::GetInstance(); MyCAS* mycas_ptr2 = MyCAS::GetInstance(); mycas_ptr->Test(); return 0; }
|
这里对new出来的对象进行回收使用到了一个小技巧,构建一个静态的GarbageCollection
对象,它的生命周期是整个程序空间,当程序全部执行完成,会析构GarbageCollection
对象,与此同时delete掉了new出的对象。
2、单例设计模式共享数据
多线程访问只读的共享数据不需要加锁进行特别的处理,这样只要在主线程中将单例类型GetInstance()
,并且装载对应的数据,其他线程就可以安全的只读这个类。但是我们可能面临着在我们自己创建的线程中创建MyCAS
这个单例类的对象(多个线程),这时我们会面临GetInstance()
这种成员函数需要互斥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include "pch.h" #include <iostream> #include <thread> #include <mutex> class MyCAS { private: MyCAS() {} private: static MyCAS* my_instance; static std::mutex my_mutex; public: static MyCAS* GetInstance() { if (NULL == my_instance) { std::unique_lock<std::mutex> mutex_guard(my_mutex); if (NULL == my_instance) { my_instance = new MyCAS(); static GarbageCollection garcolle; } return my_instance; } }
void Test() { std::cout << "Hello MyCAS " << this<<std::endl; }
class GarbageCollection // garbage collection { public: ~GarbageCollection() { if (MyCAS::my_instance) { delete MyCAS::my_instance; MyCAS::my_instance = NULL; } }
}; };
MyCAS* MyCAS::my_instance = NULL; std::mutex MyCAS::my_mutex;
void mythread() { std::cout << "我的线程 " << std::this_thread::get_id() <<" 创建。"<< std::endl; MyCAS* p_a = MyCAS::GetInstance(); std::cout << "我的线程 " << std::this_thread::get_id() <<" 执行完毕"<< std::endl; } int main() { std::thread myobj1(mythread); std::thread myobj2(mythread); myobj1.join(); myobj2.join(); return 0; }
|
3、std::call_once
std::call_once
是C++11引入的函数,该函数需要与一个标记结合使用,这个标记是std::once_flag
;该函数的第二个参数是一个函数名a()
,call_once
的功能是保证函数a()
只被调用一次。call_once
就是通过这个标记来决定对应的函数a()
是否执行,调用call_once
成功后,call_once
就把这个标记设置为一种已调用的状态,后续再次调用call_once
,只要once_flag
被设置为了”已调用”状态,那么对应的函数a()
就不会再被执行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class MyCAS { private: MyCAS() {} private: static MyCAS* my_instance; static std::mutex my_mutex; static std::once_flag g_flag;
static void CreateInstance() { my_instance = new MyCAS(); static GarbageCollection garcolle; } public: static MyCAS* GetInstance() { std::call_once(g_flag, CreateInstance); return my_instance; } };
MyCAS* MyCAS::my_instance = NULL; std::mutex MyCAS::my_mutex; std::once_flag MyCAS::g_flag;
|