欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解C++實(shí)現(xiàn)線程安全的單例模式

 更新時(shí)間:2019年03月14日 09:37:21   作者:麻子來了  
這篇文章主要介紹了C++實(shí)現(xiàn)線程安全的單例模式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

在某些應(yīng)用環(huán)境下面,一個(gè)類只允許有一個(gè)實(shí)例,這就是著名的單例模式。單例模式分為懶漢模式,跟餓漢模式兩種。

首先給出餓漢模式的實(shí)現(xiàn)

正解:

template <class T>
class singleton
{
protected:
  singleton(){};
private:
  singleton(const singleton&){};//禁止拷貝
  singleton& operator=(const singleton&){};//禁止賦值
  static T* m_instance;
public:
  static T* GetInstance();
};
 
 
template <class T>
T* singleton<T>::GetInstance()
{
  return m_instance;
}
 
template <class T>

在實(shí)例化m_instance 變量時(shí),直接調(diào)用類的構(gòu)造函數(shù)。顧名思義,在還未使用變量時(shí),已經(jīng)對m_instance進(jìn)行賦值,就像很饑餓的感覺。這種模式,在多線程環(huán)境下肯定是線程安全的,因?yàn)椴淮嬖诙嗑€程實(shí)例化的問題。

下面來看懶漢模式

template <class T>
class singleton
{
protected:
  singleton(){};
private:
  singleton(const singleton&){};
  singleton& operator=(const singleton&){};
  static T* m_instance;
public:
  static T* GetInstance();
};
 
 
template <class T>
T* singleton<T>::GetInstance()
{
  if( m_instance == NULL)
  { 
    m_instance = new T();
  }
  return m_instance;
}
 
template <class T>
T* singleton<T>::m_instance = NULL;

懶漢模式下,在定義m_instance變量時(shí)先等于NULL,在調(diào)用GetInstance()方法時(shí),在判斷是否要賦值。這種模式,并非是線程安全的,因?yàn)槎鄠€(gè)線程同時(shí)調(diào)用GetInstance()方法,就可能導(dǎo)致有產(chǎn)生多個(gè)實(shí)例。要實(shí)現(xiàn)線程安全,就必須加鎖。

下面給出改進(jìn)之后的代碼

template <class T>
class singleton
{
protected:
    singleton(){};
private:
    singleton(const singleton&){};
    singleton& operator=(const singleton&){};
    static T* m_instance;
    static pthread_mutex_t mutex;
public:
    static T* GetInstance();
};
 
 
template <class T>
T* singleton<T>::GetInstance()
{
    pthread_mutex_lock(&mutex);
    if( m_instance == NULL)
    {
        m_instance = new T();
    }
    pthread_mutex_unlock(&mutex);
    return m_instance;
}
 
 
template <class T>
pthread_mutex_t singleton<T>::mutex = PTHREAD_MUTEX_INITIALIZER;
 
template <class T>
T* singleton<T>::m_instance = NULL;

 這一切看起來都很完美,但是程序猿是一種天生就不知道滿足的動(dòng)物。他們發(fā)現(xiàn)GetInstance()方法,每次進(jìn)來都要加鎖,會(huì)影響效率。然而這并不是必須的,于是又對GetInstance()方法進(jìn)行改進(jìn)

template <class T>
T* singleton<T>::GetInstance()
{
  if( m_instance == NULL)
  {
    pthread_mutex_lock(&mutex);
    if( m_instance == NULL)
    { 
       m_instance = new T();
    }
    pthread_mutex_unlock(&mutex);
  }
  return m_instance;
}

這也就是所謂的“雙檢鎖”機(jī)制。但是有人質(zhì)疑這種實(shí)現(xiàn)還是有問題,在執(zhí)行 m_instance = new T()時(shí),可能 類T還沒有初始化完成,m_instance 就已經(jīng)有值了。這樣會(huì)導(dǎo)致另外一個(gè)調(diào)用GetInstance()方法的線程,獲取到還未初始化完成的m_instance 指針,如果去使用它,會(huì)有意料不到的后果。其實(shí),解決方法也很簡單,用一個(gè)局部變量過渡下即可:

正解:

template <class T>
T* singleton<T>::GetInstance()
{
  if( m_instance == NULL)
  {
    pthread_mutex_lock(&mutex);
    if( m_instance == NULL)
    { 
       T* ptmp = new T();
       m_instance = ptmp;
    }
    pthread_mutex_unlock(&mutex);
  }
  return m_instance;
}

到這里在懶漢模式下,也就可以保證線程安全了。

然而,在linux下面還有另一種實(shí)現(xiàn)。linux提供了一個(gè)叫pthread_once()的函數(shù),它保證在一個(gè)進(jìn)程中,某個(gè)函數(shù)只被執(zhí)行一次。下面是使用pthread_once實(shí)現(xiàn)的線程安全的懶漢單例模式

template <class T>
class singleton
{
protected:
  singleton(){};
private:
  singleton(const singleton&){};
  singleton& operator=(const singleton&){};
  static T* m_instance;
  static pthread_once_t m_once;
public:
  static void Init();
  static T* GetInstance();
};
 
 
template <class T>
void singleton<T>::Init()
{
  m_instance = new T();
}
 
template <class T>
T* singleton<T>::GetInstance()
{
  pthread_once(&m_once,Init);
  return m_instance;
}
 
template <class T>
pthread_once_t singleton<T>::m_once = PTHREAD_ONCE_INIT;
 
template <class T>
T* singleton<T>::m_instance = NULL;

 上面的單例類使用了模板,對每一種類型的變量都能實(shí)例化出唯一的一個(gè)實(shí)例。

例如要實(shí)例化一個(gè)int類型

int *p = singleton<int>::GetInstance()

例如要實(shí)例化一個(gè)string類型

string *p = singleton<string>::GetInstance()

在上面的實(shí)現(xiàn)中,在實(shí)例化對象時(shí),調(diào)用GetInstance()函數(shù)時(shí)都沒有傳遞參數(shù),這是猶豫不同的對象其初始化時(shí)參數(shù)個(gè)數(shù)都不一樣。如果要支持不同類型的對象帶參數(shù)初始化,則需要重載GetInstance函數(shù)。然而在c++11中,已經(jīng)支持了可變參數(shù)函數(shù)。這里給出一個(gè)簡單的例子

#ifndef _SINGLETON_H_
#define _SINGLETON_H_
 
template <class T>
class singleton
{
protected:
  singleton(){};
private:
  singleton(const singleton&){};
  singleton& operator=(const singleton&){};
  static T* m_instance;
public:
  template <typename... Args>
  static T* GetInstance(Args&&... args)
  {
    if(m_instance == NULL)
      m_instance = new T(std::forward<Args>(args)...);
    return m_instance;
  }
 
 
  static void DestroyInstance()
  {
    if(m_instance )
      delete m_instance;
    m_instance = NULL;
  }
};
 
 
template <class T>
T* singleton<T>::m_instance = NULL;
 
#endif

測試函數(shù)

#include <iostream>
#include <string>
#include "singleton.h"
 
using namespace std;
struct A
{
  A(int a ,int b):_a(a),_b(b)
  {}
  int _a;
  int _b;
};
 
int main()
{
  int *p1 = singleton<int>::GetInstance(5);
  int *p2 = singleton<int>::GetInstance(10);
  cout << *p1 << " " << *p2 <<endl;
  string *p3 = singleton<string>::GetInstance("aa");
  string *p4 = singleton<string>::GetInstance("bb");
 
  cout << *p3 << " " << *p4 <<endl;
 
  A *p5 = singleton<A>::GetInstance(1,2);
 
  A *p6 = singleton<A>::GetInstance(4,5);
 
  cout << p5->_a << " " << p6->_a<<endl;
  return 0;
}
 

運(yùn)行結(jié)果如下

以上所述是小編給大家介紹的C++實(shí)現(xiàn)線程安全的單例模式詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

  • C語言中的強(qiáng)符號和弱符號介紹

    C語言中的強(qiáng)符號和弱符號介紹

    這篇文章主要介紹了C語言中的強(qiáng)符號和弱符號介紹,本文用多個(gè)實(shí)例來講解強(qiáng)符號和弱符號,需要的朋友可以參考下
    2015-03-03
  • C++矩陣運(yùn)算的實(shí)現(xiàn)簡單

    C++矩陣運(yùn)算的實(shí)現(xiàn)簡單

    本文主要介紹了C++矩陣運(yùn)算的實(shí)現(xiàn)簡單,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 詳解C語言如何執(zhí)行HTTP GET請求

    詳解C語言如何執(zhí)行HTTP GET請求

    在現(xiàn)代互聯(lián)網(wǎng)時(shí)代,網(wǎng)絡(luò)數(shù)據(jù)的獲取和分析變得越來越重要,本文我們將使用C語言和libcurl庫來編寫一個(gè)簡單的網(wǎng)絡(luò)爬蟲,以執(zhí)行HTTP GET請求并獲取淘寶網(wǎng)頁的內(nèi)容,感興趣的可以了解下
    2023-11-11
  • 基于John Carmark密碼詳解

    基于John Carmark密碼詳解

    本篇文章對John Carmark密碼進(jìn)行了分析介紹。需要的朋友參考下
    2013-05-05
  • VSCode C/C++多文件編譯配置小結(jié)

    VSCode C/C++多文件編譯配置小結(jié)

    本文主要介紹了VSCode C/C++多文件編譯配置小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • C++?自定義單向鏈表?ListNode詳情

    C++?自定義單向鏈表?ListNode詳情

    這篇文章主要介紹了C++?自定義單向鏈表?ListNode詳情,文章將介紹鏈表中不帶頭結(jié)點(diǎn),沒有存放鏈表長度的節(jié)點(diǎn),從頭結(jié)點(diǎn)開始就存放數(shù)據(jù)得一種,具有一定得參考價(jià)值,需要的小伙伴可以參考一下
    2022-03-03
  • 關(guān)于C++中的static關(guān)鍵字的總結(jié)

    關(guān)于C++中的static關(guān)鍵字的總結(jié)

    C++的static有兩種用法:面向過程程序設(shè)計(jì)中的static和面向?qū)ο蟪绦蛟O(shè)計(jì)中的static。前者應(yīng)用于普通變量和函數(shù),不涉及類;后者主要說明static在類中的作用
    2013-09-09
  • C語言分支和循環(huán)詳解

    C語言分支和循環(huán)詳解

    C語言是一門結(jié)構(gòu)化的程序設(shè)計(jì)語言,當(dāng)C語言用來描述生活中的事物時(shí),會(huì)用到三種結(jié)構(gòu):順序結(jié)構(gòu)(不去贅述),選擇結(jié)構(gòu)(對應(yīng)分支語句),循環(huán)結(jié)構(gòu)(對應(yīng)循環(huán)語句),分支語句:分支語句分為兩種,一種是if語句,一種是switch語句
    2021-10-10
  • C語言每日練習(xí)之動(dòng)態(tài)顯示系統(tǒng)時(shí)間

    C語言每日練習(xí)之動(dòng)態(tài)顯示系統(tǒng)時(shí)間

    這篇文章主要介紹了C語言動(dòng)態(tài)顯示系統(tǒng)時(shí),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-11-11
  • Qt Design Studio安裝圖文教程

    Qt Design Studio安裝圖文教程

    本文主要介紹了Qt Design Studio安裝圖文教程,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02

最新評論