c++11 call_once 使用方法

call_once是c++11中引入的新特性,用於保證某個函數只調用一次,即便是多線程環境下,它也能夠可靠地完成一次函數調用。特別適用於某個初始化只執行一次的場景css

  • 若調用call_once一切順利,將會翻轉once_flag變量的內部狀態,再次調用該函數時,所對應的目標函數不會被執行
  • 若調用call_once中發生異常,不會翻轉once_flag變量的內部狀態,再次調用該函數時,目標函數仍然嘗試執行

下面代碼是在win7+vs2015編譯器測試經過,演示瞭如何使用c++11 中的call_once方法ios

#include "stdafx.h"
#include <iostream> 
#include <chrono> 
#include <thread> 
#include <mutex>

//單利模式應用 
class CSinglton
{
private:
    //(1)私有額構造函數
    CSinglton() {}
    //在析構函數中釋放實例對象
    ~CSinglton()
    {
        if (pInstance != NULL)
        {
            delete pInstance;
            pInstance = NULL;
        }
    }
public:
    //(3)得到本類實例的惟一全局訪問點
    static CSinglton* GetInstance()
    {
        //若實例不存在,則嘗試建立實例對象
        if (NULL == pInstance)
        {
            //call_once object makes sure calling CreateInstance function only one time;
            //it will be safe without lock;
            try 
            {
                std::call_once(m_flag, CreateInstance);
            }
            catch (...) 
            {
                std::cout << "CreateInstance error\n";
            }

        }
        //實例已經存在,直接該實例對象
        return pInstance;
    }

    static void CreateInstance()
    {
        pInstance = new(std::nothrow) CSinglton();//分配失敗,是返回NULL;
        if (NULL == pInstance)
        {
            throw std::exception();
        }
    }

private:
    static CSinglton* pInstance;//(2)惟一實例對象
    static std::once_flag m_flag;
};

CSinglton*          CSinglton::pInstance = NULL;
//構造 once_flag 對象,內部狀態被設爲指示函數仍未被調用。 
std::once_flag      CSinglton::m_flag;


//輔助測試代碼
std::mutex g_mutex;
void  PrintInstanceAddr()
{
    std::this_thread::sleep_for(std::chrono::microseconds(1));

    //get instance 
    CSinglton* pIns = CSinglton::GetInstance();

    //print instance addr
    std::lock_guard<std::mutex> lock(g_mutex);
    std::cout << pIns << std::endl;
}


int main()
{
    std::thread td[5];

    //multhread get instance addr;
    for (int i = 0; i < 5; i++)
    {
        td[i] = std::thread(PrintInstanceAddr);
    }

    for (int i = 0; i < 5; i++)
    {
        td[i].join();
    }

    return 0;
}

運行結果:c++

0076E778
0076E778
0076E778
0076E778
0076E778

參考資料:
http://zh.cppreference.com/w/cpp/thread/call_once
http://www.cplusplus.com/reference/mutex/call_once/?kw=call_oncemarkdown

相關文章
相關標籤/搜索