muduo網路庫學習筆記(6):單例類(執行緒安全的)

li27z發表於2016-08-15

muduo用pthread_once實現了執行緒安全的Singleton。

檔名:Singleton.h

template<typename T>
class Singleton : boost::noncopyable
{
public:
    static T& instance()
    {
        pthread_once(&ponce_, &Singleton::init);
        return *value_;
    }

private:
    Singleton();
    ~Singleton();
    static void init()
    {
        value_ = new T();
    }

    static pthread_once_t ponce_;
    static T* value_;
};

template<typename T>
pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT;

template<typename T>
T* Singleton<T>::value_ = NULL;

使用方法也很簡單:

Foo& foo = Singleton<Foo>::instance();

其中有哪些知識點呢?
(1)瞭解單例模式
實際應用中,有些物件,我們只需要一個就可以了,比如,一臺計算機上可以連好幾個印表機,但是這個計算機上的列印程式只能有一個,這裡就可以通過單例模式來避免兩個列印作業同時輸出到印表機中,即在整個的列印過程中只有一個列印程式的例項。

單例模式是一種常用的軟體設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中一個類只有一個例項。

(2)pthread_once

#include <pthread.h>

int pthread_once(pthread_once_t *once_control,
                 void (*init_routine)(void));
pthread_once_t once_control = PTHREAD_ONCE_INIT;

本函式使用初值為PTHREAD_ONCE_INIT的once_control變數保證init_routine()函式在本程式執行序列中僅執行一次,且能保證執行緒安全。(我們還能用互斥鎖的方式來實現執行緒安全,但效率沒有pthread_once高)

(3)atexit

// atexit()函式用來註冊程式正常終止時要被呼叫的函式
// 在一個程式中最多可以用atexit()註冊32個處理函式
// 這些處理函式的呼叫順序與其註冊的順序相反
// 即最先註冊的最後呼叫,最後註冊的最先呼叫

#include<stdlib.h>

int atexit(void (*func)(void));  // 登記的函式型別為不接受任何引數的void函式

在Singleton.h中,atexit函式被用於註冊一個銷燬函式,在程式結束的時候會自動呼叫銷燬函式,就不用手動呼叫了。

(4)typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1];
在C++中,型別有Complete type和Incomplete type之分,對於Complete type, 它的大小在編譯時是可以確定的,而對於Incomplete type, 它的大小在編譯時是不能確定的。
用delete刪除一個只有宣告但無定義的型別的指標(即不完整型別),是危險的。這通常導致無法呼叫解構函式(包括物件本身的解構函式、成員/基類的解構函式),從而洩露資源。
而通過 typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; 這種做法能使當T為不完整型別時編譯報錯。(當T為不完整型別時,sizeof(T)給出的是0,根據程式碼規則,-1是不能作為陣列的size的,因此,這裡相當於強制編譯器給出error而不是 warning)

相關文章