首页 > 代码库 > C++——单例模式的DCLP(双重锁)实现以及性能测评
C++——单例模式的DCLP(双重锁)实现以及性能测评
单例模式的描述是: 确保一个类只有一个实例,并提供对该实例的全局访问。
从这段话,我们可以知道,单例模式的最重要特点就是:一个类最多只有一个对象。
对于一个普通类,我么可以生成任意对象,我们为了避免生成太多的类,需要将类的构造函数设为私有。
这样的话,我们为了获取实例,只能借助于类的内部函数,而且必须是static函数(非static函数中均包含一个隐式参数this,由于我们没办法实例化,所以只能通过static函数来获取实例):
1 class Singleton 2 { 3 public: 4 static Singleton *getInstance() 5 { 6 return new Singleton; 7 } 8 private: 9 Singleton() { }10 };
这样虽然可以生成对象了,但每次都去new,无法保证唯一性,所以我们将对象保存在一个static 指针中:
1 class Singleton 2 { 3 public: 4 static Singleton *getInstance() 5 { 6 if(pInstance_ == NULL) //线程的切换 7 { 8 ::sleep(1); 9 pInstance_ = new Singleton;10 }11 12 return pInstance_;13 }14 private:15 Singleton() { }16 17 static Singleton *pInstance_;18 };19 20 Singleton *Singleton::pInstance_ = NULL;
这样我们每次获取对象时,都会检查该指针是否为空。
这样虽然在单线程中可以通过测试,但在多线程中,由于线程的切换,我们生成的对象将不唯一。
所以,我们需要通过加锁来解决这个问题:
1 class Singleton 2 { 3 public: 4 static Singleton *getInstance() 5 { 6 mutex_.lock(); 7 if(pInstance_ == NULL) //线程的切换 8 pInstance_ = new Singleton; 9 mutex_.unlock();10 return pInstance_;11 }12 private:13 Singleton() { }14 15 static Singleton *pInstance_;16 static MutexLock mutex_;17 };18 19 Singleton *Singleton::pInstance_ = NULL;20 MutexLock Singleton::mutex_;
加锁后,虽然解决了这种问题,可是互斥锁会极大的降低系统的并发能力,因为每次调用都要加锁。
测试代码如下:
1 class TestThread : public Thread 2 { 3 public: 4 void run() 5 { 6 const int kCount = 1000 * 1000; 7 for(int ix = 0; ix != kCount; ++ix) 8 { 9 Singleton::getInstance();10 }11 }12 };13 14 int64_t getUTime()15 {16 struct timeval tv;17 ::memset(&tv, 0, sizeof tv);18 if(gettimeofday(&tv, NULL) == -1)19 {20 perror("gettimeofday");21 exit(EXIT_FAILURE);22 }23 int64_t current = tv.tv_usec;24 current += tv.tv_sec * 1000 * 1000;25 return current;26 }27 28 int main(int argc, char const *argv[])29 {30 //Singleton s; ERROR31 32 int64_t startTime = getUTime();33 34 const int KSize = 100;35 TestThread threads[KSize];36 for(int ix = 0; ix != KSize; ++ix)37 {38 threads[ix].start();39 }40 41 for(int ix = 0; ix != KSize; ++ix)42 {43 threads[ix].join();44 }45 46 int64_t endTime = getUTime();47 48 int64_t diffTime = endTime - startTime;49 cout << "cost : " << diffTime / 1000 << " ms" << endl;50 51 return 0;52 }
测试结果如下:
cost : 7304 ms
我们可以采用双重锁模式来提高性能。
1 class Singleton 2 { 3 public: 4 static Singleton *getInstance() 5 { 6 if(pInstance_ == NULL) 7 { 8 mutex_.lock(); 9 if(pInstance_ == NULL) //线程的切换10 pInstance_ = new Singleton;11 mutex_.unlock();12 }13 14 return pInstance_;15 }16 private:17 Singleton() { }18 19 static Singleton *pInstance_;20 static MutexLock mutex_;21 };22 23 Singleton *Singleton::pInstance_ = NULL;24 MutexLock Singleton::mutex_;
我们在getInstance中采用了双重检查模式,这样做的优点为:
内部采用互斥锁,代码无论如何是可靠的
new出第一个实例后,后面每个线程访问到最外面的if判断就直接返回了,没有加锁的开销
再次测试,结果为:
cost : 486 ms
这样,就简单的完成了对单例模式的一点性能改进。
C++——单例模式的DCLP(双重锁)实现以及性能测评
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。