日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++Singleton的DCLP(双重锁)实现以及性能测评

發布時間:2023/12/20 c/c++ 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++Singleton的DCLP(双重锁)实现以及性能测评 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

?

本文系原創,轉載請注明:http://www.cnblogs.com/inevermore/p/4014577.html

?

根據維基百科,對單例模式的描述是:

確保一個類只有一個實例,并提供對該實例的全局訪問。

從這段話,我們可以得出單例模式的最重要特點:

一個類最多只有一個對象

?

單線程環境

?

對于一個普通的類,我們可以任意的生成對象,所以我們為了避免生成太多的類,需要將類的構造函數設置為私有。

所以我們寫出第一步:

class Singleton { public:private:Singleton() { } };

此時在main中就無法直接生成對象:

Singleton s; //ERROR

那么我們想要獲取實例,只能借助于類內部的函數,于是我們添加一個內部的函數,而且必須是static函數(思考為什么):

class Singleton { public:static Singleton *getInstance(){return new Singleton;} private:Singleton() { } }; OK,我們可以用這個函數生成對象了,但是每次都去new,無法保證唯一性,于是我們將對象保存在一個static指針內,然后每次獲取對象時,先檢查該指針是否為空: class Singleton { public:static Singleton *getInstance(){if(pInstance_ == NULL) //線程的切換 {::sleep(1);pInstance_ = new Singleton;}return pInstance_;} private:Singleton() { }static Singleton *pInstance_; };Singleton *Singleton::pInstance_ = NULL;

我們在main中測試:

cout << Singleton::getInstance() << endl; cout << Singleton::getInstance() << endl;

可以看到生成了相同的對象,單例模式編寫初步成功。

?

多線程環境下的考慮

?

但是目前的代碼就真的沒問題了嗎?

我寫出了以下的測試:

class TestThread : public Thread { public:void run(){cout << Singleton::getInstance() << endl;cout << Singleton::getInstance() << endl;} };int main(int argc, char const *argv[]) {//測試證明了多線程下本代碼存在競爭問題 TestThread threads[12];for(int ix = 0; ix != 12; ++ix){threads[ix].start();}for(int ix = 0; ix != 12; ++ix){threads[ix].join();}return 0; }

?

這里注意,為了達到效果,我特意做了如下改動:

if(pInstance_ == NULL) //線程的切換 {::sleep(1);pInstance_ = new Singleton; }

這樣故意造成線程的切換

打印結果如下:

0xb1300468 0xb1300498 0x9f88728 0xb1300498 0xb1300478 0xb1300498 0xb1100488 0xb1300498 0xb1300488 0xb1300498 0xb1300498 0xb1300498 0x9f88738 0xb1300498 0x9f88748 0xb1300498 0xb1100478 0xb1300498 0xb1100498 0xb1300498 0xb1100468 0xb1300498 0xb11004a8 0xb11004a8

?

很顯然,我們的代碼在多線程下經不起推敲。

怎么辦?加鎖! 于是我們再度改進:

class Singleton { public:static Singleton *getInstance(){mutex_.lock();if(pInstance_ == NULL) //線程的切換pInstance_ = new Singleton;mutex_.unlock();return pInstance_;} private:Singleton() { }static Singleton *pInstance_;static MutexLock mutex_; };Singleton *Singleton::pInstance_ = NULL; MutexLock Singleton::mutex_;

此時測試,無問題。

但是,互斥鎖會極大的降低系統的并發能力,因為每次調用都要加鎖,等于一群人過獨木橋

我寫了一份測試如下:

class TestThread : public Thread { public:void run(){const int kCount = 1000 * 1000;for(int ix = 0; ix != kCount; ++ix){Singleton::getInstance();}} };int main(int argc, char const *argv[]) {//Singleton s; ERROR int64_t startTime = getUTime();const int KSize = 100;TestThread threads[KSize];for(int ix = 0; ix != KSize; ++ix){threads[ix].start();}for(int ix = 0; ix != KSize; ++ix){threads[ix].join();}int64_t endTime = getUTime();int64_t diffTime = endTime - startTime;cout << "cost : " << diffTime / 1000 << " ms" << endl;return 0; }

開了100個線程,每個調用1M次getInstance,其中getUtime的定義如下:

int64_t getUTime() {struct timeval tv;::memset(&tv, 0, sizeof tv);if(gettimeofday(&tv, NULL) == -1){perror("gettimeofday");exit(EXIT_FAILURE);}int64_t current = tv.tv_usec;current += tv.tv_sec * 1000 * 1000;return current; }

運行結果為:

cost : 6914 ms

?

?

采用雙重鎖模式

?

上面的測試,我們還無法看出性能問題,我再次改進代碼:

class Singleton { public:static Singleton *getInstance(){if(pInstance_ == NULL){mutex_.lock();if(pInstance_ == NULL) //線程的切換pInstance_ = new Singleton;mutex_.unlock();}return pInstance_;} private:Singleton() { }static Singleton *pInstance_;static MutexLock mutex_; };Singleton *Singleton::pInstance_ = NULL; MutexLock Singleton::mutex_;

可以看到,我在getInstance中采用了兩重檢查模式,這段代碼的優點體現在哪里?

內部采用互斥鎖,代碼無論如何是可靠的

new出第一個實例后,后面每個線程訪問到最外面的if判斷就直接返回了,沒有加鎖的開銷

我再次運行測試,(測試代碼不變),結果如下:

cost : 438 ms

啊哈,十幾倍的性能差距,可見我們的改進是有效的,僅僅三行代碼,卻帶來了十幾倍的效率提升!

?

尾聲

?

上面這種編寫方式成為DCLP(Double-Check-Locking-Pattern)模式,這種方式一度被認為是絕對正確的,但是后來有人指出這種方式在某些情況下也會亂序執行,可以參考Scott的C++ and the Perils of Double-Checked Locking - Scott Meyer

轉載于:https://my.oschina.net/inevermore/blog/388676

總結

以上是生活随笔為你收集整理的C++Singleton的DCLP(双重锁)实现以及性能测评的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。