為什麼要使用單例?
一個類隻允許建立一個對象或者執行個體。
背景簡介:使用多線程并發通路同一個類,為了保證類的線程安全,可以有兩種方法:
- 将該類定義為單例模式,即該類僅允許建立一個執行個體
- 為該類的成員函數添加類級别的鎖
舉例:
一個向指定檔案寫入日志的類,為了保證該類并發調用時寫入檔案的日志不會覆寫,需執行以上操作。
單例模式的幾種經典的實作方式:
-
餓漢式
在類的加載期間,将靜态執行個體初始化好,是以執行個體的建立是線程安全的。但是這樣的方式不支援延遲加載,且每加載一個執行個體都會重新初始化一次,開銷較大。
-
懶漢式
懶漢模式相對于餓漢模式的優點是支援延遲加載(C++ 種的動态綁定),隻有執行個體化的時候才知道該對象的執行個體。但是會導緻出現頻發加鎖,釋放鎖造成效率底下 的問題。
-
雙重檢測
雙重檢測既支援延遲加載,又支援高并發的單例實作方式。
-
靜态内部類
JAVA支援的靜态内部類實作單例。這種實作方式既支援延遲加載,也支援高并發執行個體,實作起來也比雙重檢測簡單。
-
枚舉
最簡單的實作方式,基于枚舉實作的單例。通過枚舉類型本身的特性,保證了執行個體建立的線程安全性和執行個體的唯一性。
C語言單例模式的實作:
餓漢模式
csingleton.h
#ifndef CSINGLETON_H
#define CSINGLETON_H
#include <stdlib.h>
typedef struct {
void* (*ctor)(void *_self);
void* (*dtor)(void *_self);
void* (*createInstance)(void *self);
void *instance;
} _CSingleton;
extern const void *CSingleton;
void *GetInstance(void);
#endif
csingleton.c
#include "csingleton.h"
#include <stdlib.h>
static void *csingletonCtor(void *_self) {
_CSingleton *self = _self;
self->instance = _self;
return self;
}
static void *csingletonDtor(void *_self) {
_CSingleton *self = _self;
self->instance = NULL;
return self;
}
static void *csingletonCreateInstance(void *_self) {
_CSingleton *self = _self;
self->instance = _self;
return self;
}
static _CSingleton _csingleton = {
csingletonCtor, csingletonDtor, csingletonCreateInstance, NULL
};
const void *CSingleton = &_csingleton;
void *GetInstance(void) { //當調用該函數加載類的時候進行初始化
if (NULL == ((_CSingleton*)CSingleton)->instance) {
return csingletonCtor(CSingleton);
} else {
return ((_CSingleton*)CSingleton)->instance;
}
}
main.c
#include "csingleton.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
void *ps1 = GetInstance();
void *ps2 = GetInstance();
if (ps1 == ps2) {
fprintf(stdout, "ps1 = ps2\n");
}
return 0;
}
懶漢模式
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <omp.h>
typedef struct ID{
char *name;
int id_num;
}id;
static id *_id = NULL;
/*通過鎖進行并發通路時線程間競争的控制*/
static omp_lock_t lock;
id *getInstance(){
omp_set_lock(&lock);
if(NULL != _id) {
omp_unset_lock(&lock);
return _id;
} else {
_id = (id*)malloc(sizeof(id));
assert(_id != NULL);
omp_unset_lock(&lock);
return _id;
}
}
int main(int argc, char *argv[]) {
omp_set_num_threads(20);//運作時的庫函數,設定運作的線程數目
id * i1, *i2;
omp_init_lock(&lock);
{
i1 = getInstance() ;
i1->name = "Rong";
i1->id_num = omp_get_thread_num();
}
{
i2 = getInstance() ;
i2->name = "Tao";
}
omp_destroy_lock(&lock);
if(i1 == i2){
fprintf(stdout, " i1 == i2 \n");
}
fprintf(stdout, "i1->name = %s, i1->score = %d\n",i1->name, i1->id_num);
fprintf(stdout, "i2->name = %s, i2->score = %d\n",i2->name, i2->id_num);
return 0;
}
C++實作單例模式
#include <iostream>
using namespace std;
class Singleon
{
private:
Singleon()
{
cout << "Singleon()" << endl;
}
static Singleon* instance;
public:
static Singleon* GetSingleon()
{
return instance;
}
static Singleon* Destroy()
{
delete instance;
instance = NULL;
}
};
/*編譯加載類的時候即初始化,靜态成員編譯的時候即會初始化*/
Singleon* Singleon::instance = new Singleon();
int main()
{
Singleon* sl1 = Singleon::GetSingleon();
Singleon* sl2 = Singleon::GetSingleon();
Singleon* sl3 = Singleon::GetSingleon();
cout << sl1 << endl;
cout << sl2 << endl;
cout << sl2 << endl;
system("pause");
return 0;
}
#include <iostream>
using namespace std;
class Singleon
{
private:
Singleon()
{
cout << "Singleon()" << endl;
}
static Singleon*instrance;
public:
static Singleon* GetSingleon()
{
if (NULL == instrance)
{
instrance = new Singleon();
cout << "對象建立成功" << endl;
}
else
{
cout << "對象已經建立成功,無須再建" << endl;
}
return instrance;
}
static Singleon* Destroy()
{
delete instrance;
instrance = NULL;
}
};
/*類加載的時候不進行初始化,執行個體化的時候進行初始化*/
Singleon* Singleon::instrance = NULL;
int main()
{
Singleon* sl1 = Singleon::GetSingleon();
Singleon* sl2 = Singleon::GetSingleon();
Singleon* sl3 = Singleon::GetSingleon();
cout << sl1 << endl;
cout << sl2 << endl;
cout << sl2 << endl;
system("pause");
return 0;
}