单例类:

(1) 单例类保证全局只有一个唯一的实例对象。

(2) 单例类保证只有唯一的接口获取这唯一实例。

非线程安全的单例类举例:

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 class CSingleton 2 { 3 public: 4     ~CSingleton(){} 5     static CSingleton * getInstance() 6     { 7         if (m_instance == nullptr) 8         { 9             m_instance = new CSingleton;10         }11         return m_instance;12     }13     static void delInstance()14     {15         if (m_instance)16         {17             delete m_instance;18             m_instance = nullptr;19         }20     }21     void print()22     {23         std::cout << "print test" << std::endl;24     }25 private:26     CSingleton(){}27     CSingleton & operator=(const CSingleton & ) = delete;28     CSingleton(const CSingleton &) = delete;29 private:30     static CSingleton * m_instance;31 };32 33 CSingleton * CSingleton::m_instance = nullptr;

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

上述单例类面对多线程并发访问时会出错。

看如下线程安全的单例类(非C++11实现)

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 class CSingleton 2 { 3 public: 4     ~CSingleton() {} 5     static CSingleton * getInstance() 6     { 7         if (m_instance == nullptr) 8         { 9             std::lock_guard<std::mutex> lgd(m_mt);10             if (m_instance == nullptr)11             {12                 m_instance = new CSingleton;13             }14         }15         return m_instance;16     }17     static void delInstance()18     {19         std::lock_guard<std::mutex> lgd(m_mt);20         if (m_instance)21         {22             delete m_instance;23             m_instance = nullptr;24         }25     }26     void print()27     {28         std::cout << "print test" << std::endl;29     }30 private:31     CSingleton() {}32     CSingleton & operator=(const CSingleton & ) = delete;33     CSingleton(const CSingleton &) = delete;34 private:35     static CSingleton * m_instance;36     static std::mutex m_mt;37 };38 39 CSingleton * CSingleton::m_instance = nullptr;40 std::mutex CSingleton::m_mt;

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

当然绝对的线程安全还是有问题,因为C++创建对象时,会执行分配内存,调用构造,赋值操作三部分完成,然而现代CPU和编译器高并发下可能

会进行乱序重排操作,因而创建对象new CSingleton的第二步可能会晚于第三步进行指令调用,因而导致出现未定义的的行为,固需要引入内存栅栏来确保指令运行的同步性。(理解下,具体实现还需要探究)

C++11的单例模式的实现

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 class CSingleton 2 { 3 public: 4     ~CSingleton() {} 5     static CSingleton & getInstance() 6     { 7         static CSingleton m_instance; 8         return m_instance; 9     }10     void print()11     {12         std::cout << "print test" << std::endl;13     }14 };

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

返回静态局部对象的引用,C++11中是线程安全的。

验证一下:

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 class CStatic 2 { 3 public: 4     CStatic() 5     { 6         std::cout << "construct begin" << std::endl; 7         Sleep(5000); 8         std::cout << "construct end" << std::endl; 9     }10     void print()11     {    12         std::cout << "print" << std::endl;13         std::cout << s_num++ << std::endl;14     }15     static int s_num;16     static std::mutex s_mt;17 };

大学生就业培训,高中生培训,在职人员转行培训,企业团训

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 int CStatic::s_num = 0; 2 std::mutex CStatic::s_mt; 3  4 // 5 void thread_func() 6 { 7     static CStatic st; 8     st.print(); 9 }10 11 int main()12 {13     std::vector<std::thread> vecThread;14     for (auto i = 0; i< 8; i++)15     {16         vecThread.push_back(std::thread(thread_func));17     }18     for (auto i = 0; i< 8; i++)19     {20         vecThread[i].join();21     }22     //23     system("pause");24     return 0;25 }

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

首先我们创建一个CStatic类,然后创建8个线程来启动thread_func(),thread_func()初始化了一个静态CStatic对象,(静态局部变量仅被初始化一次)

然后接着运行。我们发现,当首个线程初始化CStatic时,其他线程都是被阻塞的,从构造函数的begin和end中可以看到,我们故意让其停留5s,

如下图,其他线程都是在st被初始化之后才运行。

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

所以CStatic静态局部对象被构造的过程中是线程安全的,但是其拥有的成员变量则不是线程安全的,看print函数打印出来的结果print和s_num则是乱序的。

因此我们增加个简单的锁,

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 1 class CStatic 2 { 3 public: 4     CStatic() 5     { 6         std::cout << "construct begin" << std::endl; 7         Sleep(5000); 8         std::cout << "construct end" << std::endl; 9     }10     void print()11     {    
12         std::lock_guard<std::mutex> lgd(s_mt);13         std::cout << "print" << std::endl;14         std::cout << s_num++ << std::endl;15     }16     static int s_num;17     static std::mutex s_mt;18 };

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

看结果,按顺序打印出来:

大学生就业培训,高中生培训,在职人员转行培训,企业团训

 

继续C++11的学习,加油!!!

书到用时方恨少,是非经过不知难。 博观而约取,厚积而薄发。@karllen 每天进步一点点。

http://www.cnblogs.com/Forever-Kenlen-Ja/p/7050300.html