餓漢模式:
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的操作。