C++ 單例模式實現


C++ 單例模式(懶漢、餓漢模式)

C++實現單例模式(包括采用C++11中的智能指針)

 

餓漢模式:

class CSingleton    
{    
private:    
    CSingleton()      
    {    
    }    
public:    
    static CSingleton * GetInstance()    
    {    
        static CSingleton instance;     
        return &instance;    
    }    
};
————————————————
版權聲明:本文為CSDN博主「zhanghuaichao」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zhanghuaichao/article/details/79459130

 

多線程下的懶漢模式

class Singleton  
{  
private:  
    static Singleton* m_instance;  
    Singleton(){}  
public:  
    static Singleton* getInstance();  
};  
  
Singleton* Singleton::getInstance()  
{  
    if(NULL == m_instance)  
    {  
        Lock();//借用其它類來實現,如boost  
        if(NULL == m_instance)  
        {  
            m_instance = new Singleton;  
        }  
        UnLock();  
    }  
    return m_instance;  
}
————————————————
版權聲明:本文為CSDN博主「zhanghuaichao」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zhanghuaichao/article/details/79459130

 

懶漢:故名思義,不到萬不得已就不會去實例化類,也就是說在第一次用到類實例的時候才會去實例化。與之對應的是餓漢式單例。(注意,懶漢本身是線程不安全的,如上例子)

餓漢:餓了肯定要飢不擇食。所以在單例類定義的時候就進行實例化。(本身就是線程安全的,如下例子)

關於如何選擇懶漢和餓漢模式:

特點與選擇:

  懶漢:在訪問量較小時,采用懶漢實現。這是以時間換空間。

  餓漢:由於要進行線程同步,所以在訪問量比較大,或者可能訪問的線程比較多時,采用餓漢實現,可以實現更好的性能。這是以空間換時間。

3、餓漢式的單例實現

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
#include <iostream>
#include <process.h>
#include <windows.h>
using  namespace  std;
 
class  Singelton{
private :
     Singelton(){
         m_count ++;
         printf ( "Singelton begin\n" );
         Sleep(1000);                             // 加sleep為了放大效果
         printf ( "Singelton end\n" );
     }
     static  Singelton *single;
public :
     static  Singelton *GetSingelton();
     static  void  print();
     static  int  m_count;
};
// 餓漢模式的關鍵:初始化即實例化
Singelton *Singelton::single =  new  Singelton;
int  Singelton::m_count = 0;
 
Singelton *Singelton::GetSingelton(){
     // 不再需要進行實例化
     //if(single == nullptr){
     //    single = new Singelton;
     //}
     return  single;
}
 
void  Singelton::print(){
     cout<<m_count<<endl;
}
// 回調函數
void  threadFunc( void  *p){
     DWORD  id = GetCurrentThreadId();         // 獲得線程id
      cout<<id<<endl;
     Singelton::GetSingelton()->print();       // 構造函數並獲得實例,調用靜態成員函數
}
 
int  main( int  argc,  const  char  * argv[]) {
     int  threadNum = 3;
     HANDLE  threadHdl[100];
     
     // 創建3個線程
     for ( int  i = 0; i<threadNum; i++){
         threadHdl[i] = ( HANDLE )_beginthread(threadFunc, 0,  nullptr );
     }
     
     // 讓主進程等待所有的線程結束后再退出
     for ( int  i = 0; i<threadNum; i++){
         WaitForSingleObject(threadHdl[i], INFINITE);
     }
     cout<< "main" <<endl;                  // 驗證主進程是否是最后退出
     return  0;
}

  運行結果:

4、線程安全的懶漢式單例的實現

餓漢式會提前浪費我們的內存空間以及資源,如果有項目中要求我們在使用到實例的時候再去實例化,則還是需要使用懶漢式。

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
class  singleton
{
protected :
     singleton()
     {
         // 初始化
         pthread_mutex_init(&mutex);
     }
private :
     static  singleton* p;
public :
     static  pthread_mutex_t mutex;
     static  singleton* initance();
};
 
pthread_mutex_t singleton::mutex;
singleton* singleton::p = NULL;
singleton* singleton::initance()
{
     if  (p == NULL)
     {
         // 加鎖
         pthread_mutex_lock(&mutex);
         if  (p == NULL)
             p =  new  singleton();
         pthread_mutex_unlock(&mutex);
     }
     return  p;
}

  需要注意的是:上面進行的兩次if(p == NULL)的檢查,因為當獲得了實例之后,有了外層的判斷之后,就不會再進入到內層判斷,即不會再進行lock以及unlock的操作。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM