1. 程式人生 > >C++ Singleton單例實現方式

C++ Singleton單例實現方式

1.singleton模式的意圖是什麼?或者說使用singleton模式解決的問題是什麼? 答:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點,該例項被所有程式模組共享!!! 2.解決上述問題的方法: 方法一: 全域性變數或是靜態變數 此方法存在的問題:這樣做雖然能保證方便的訪問例項,但是不能保證只宣告一個物件——也就是說除了一個全域性例項外,仍然能建立此類的區域性例項。當然一不小心可能再建立另一個全域性的例項。 方法二:自己實現個簡單的單例(C++版本)。
#ifndef SINGLETON_H
#define SINGLETON_H
#include<stddef.h>
#include<iostream>
#include<mutex>
using namespace std;
namespace test
{
std::mutex g_mutex;
template <typename T>
class Singleton
{
public:
    static T* get()
    {

        if(m_instance_==NULL)
        {
            g_mutex.lock();
            if(m_instance_==NULL)
            {   
                m_instance_=new T();
            }
            g_mutex.unlock();
        }
        return m_instance_;
    }

private:
    Singleton(){}
    static T* m_instance_;
};
template<typename T>
T* Singleton<T>::m_instance_=NULL;
}
#endif
上述程式碼有三個點需要說明下: 1.多執行緒:為防止多執行緒情況下產生多個單例指標,所以需要新增g_mutex來實現加鎖和解鎖。 2.double-check:就是if(m_instance_==NULL) 做了兩次判斷,別的文章說如果不double-check會導致多個執行緒訪問get函式時導致過多執行緒掛起,這句話我的體會不深,理解不深刻,鸚鵡學舌了! 3.現在發現,這個單例模式沒有釋放類T的例項的操作!——貌似智慧指標auto_ptr能解決這個問題,或是新增Delete()函式,在某個適當的時候集中銷燬! 4.還有建構函式宣告為private能夠防止在singleton外隨意的例項化!
答:亦可以防止防止做為基類使用呀!和 5 的作用豈不是重複了? 5.還有將解構函式宣告為private,這種設計我目前還不太理解是為什麼? 答:應該是防止被做為基類使用!(2017.02.22) 6.在使用多執行緒測試此段程式碼時,使用g++做編譯的命令格式是: g++ -std=c++0x  -Wl,--no-as-needed  main.cpp  -pthread -o test.out main.cpp部分的程式碼如下:
#include"./Singleton.h"
#include<iostream>
#include<thread>
using namespace std;

class Me
{
public:
    void Say()
    {   
        std::cout<<"Hello Word"<<std::endl;
    }
};
void hello()
{
    while(true)
    {
        cout<<"he"<<endl;
    }
}
int main()
{   
    thread first(&test::Singleton<Me>::get);
    thread second(&test::Singleton<Me>::get);
    thread third(&test::Singleton<Me>::get);
    
    first.join();
    second.join();
    third.join();
    return 0;
}

2017年2月27日更新以下內容: 無鎖結構的實現方式,但是經試驗驗證,以現在程式碼的實現方式,耗時和有鎖結構相比無明顯區別: 這可能是因為獲得鎖之後的程式碼只需要瞬間的執行時間,從而沒有明顯因為等待鎖而導致程式碼耗時增加! 程式碼中的__sync_val_compare_and_swap(&m_flag_,0,1) 
#ifndef SINGLETON_H
#define SINGLETON_H
//template <typename T>
#include<stddef.h>
#include<iostream>
#include<mutex>
using namespace std;
namespace test
{
//std::mutex g_mutex;
template <typename T>
class Singleton
{
public:
    static T* get()
    {

        if(0==__sync_val_compare_and_swap(&m_flag_,0,1))
        {
            //g_mutex.lock();
            if(m_instance_==NULL)
            {
            //std::cout<<"get"<<std::endl;
                m_instance_=new T();
                std::cout<<"ptra:"<<m_instance_<<std::endl;
            }
            //g_mutex.unlock();
        }
        std::cout<<"already-1:"<<m_instance_<<std::endl;
        return m_instance_;
    }

private:
    Singleton(){}
    static int m_flag_;
    static T* m_instance_;
};
template<typename T>
T* Singleton<T>::m_instance_=NULL;
template<typename T>
int Singleton<T>::m_flag_=0;
}
#endif


#include"./Singleton.h"
#include<iostream>
#include<thread>

#include<sys/time.h>
using namespace std;

class Me
{
public:
    void Say()
    {
        std::cout<<"Hello Word"<<std::endl;
    }
};
void hello()
{
    while(true)
    {
        cout<<"he"<<endl;
    }
}
#define N 10000
int main()
{
    //Me* p[10]={NULL};
    //Me* p=test::Singleton<Me>::get();
    //p->Say();

    //thread t(hello);
    //t.join();
    struct timeval start,end;
    gettimeofday(&start,NULL);
    thread pool[N];
    for(int i=0;i<N;i++)
    {
        pool[i]=thread(&test::Singleton<Me>::get);
    }
    for(int i=0;i<N;i++)
    {
        pool[i].join();
       }
    gettimeofday(&end,NULL);
    std::cout<<std::endl;
    std::cout<<"total time:"<<double((end.tv_sec-start.tv_sec)*1000000+(end.tv_usec-start.tv_usec))<<std::endl; 
    return 0;
}