天天看點

設計模式 之美 -- 單例模式

為什麼要使用單例?

一個類隻允許建立一個對象或者執行個體。

背景簡介:使用多線程并發通路同一個類,為了保證類的線程安全,可以有兩種方法:
  1. 将該類定義為單例模式,即該類僅允許建立一個執行個體
  2. 為該類的成員函數添加類級别的鎖

舉例:

一個向指定檔案寫入日志的類,為了保證該類并發調用時寫入檔案的日志不會覆寫,需執行以上操作。

單例模式的幾種經典的實作方式:

  • 餓漢式

    在類的加載期間,将靜态執行個體初始化好,是以執行個體的建立是線程安全的。但是這樣的方式不支援延遲加載,且每加載一個執行個體都會重新初始化一次,開銷較大。

  • 懶漢式

    懶漢模式相對于餓漢模式的優點是支援延遲加載(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;
}