C++singleton's DCLP (double lock) implementation and performance evaluation

Source: Internet
Author: User

This article is original, reproduced please specify: http://www.cnblogs.com/inevermore/p/4014577.html

According to Wikipedia, the description of the singleton pattern is:

Ensure that a class has only one instance and provides global access to the instance.

From this passage, we can draw the most important features of the Singleton pattern:

A class has only one object at most

Single Thread Environment

For an ordinary class, we can generate the object arbitrarily, so we need to set the constructor of the class to private in order to avoid generating too many classes.

So we write the first step:

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

At this point, the object cannot be generated directly in main:

// ERROR

So we want to get the instance, only with the help of the function inside the class, so we add an inner function, and it must be a static function (think about why):

class singleton{public:    static Singleton *getinstance ()    {         return New Singleton;    } Private :    Singleton () {}};
OK, we can use this function to generate the object, but every time we go to new, we cannot guarantee uniqueness, so we save the object in a static pointer, and then each time we get the object, we first check whether the pointer is empty:
classsingleton{ Public:    StaticSingleton *getinstance () {if(Pinstance_ = = NULL)//Switching of Threads{:: Sleep (1); Pinstance_=NewSingleton; }                    returnPinstance_; }Private: Singleton () {}StaticSingleton *Pinstance_;}; Singleton*singleton::p instance_ = NULL;

We test in main:

cout << singleton::getinstance () <<<< singleton::getinstance () << Endl;

You can see that the same object was generated, and the singleton pattern was initially successfully written.

Considerations in multi-threaded environments

But is the code really going to be okay?

I have written the following tests:

classTestthread: Publicthread{ Public:    voidrun () {cout<< singleton::getinstance () <<Endl; cout<< singleton::getinstance () <<Endl; }};intMainintargcChar Const*argv[]) {    //test proves that there is a competition problem in this code under multithreadingTestthread threads[ A];  for(intIX =0; IX! = A; ++ix) {Threads[ix].start (); }     for(intIX =0; IX! = A; ++ix) {threads[ix].join (); }    return 0;}

Note here that in order to achieve the effect, I made the following changes:

if // Switching of Threads {     :: Sleep (1);      New Singleton;}

This intentionally causes the thread to switch .

The printing results are as follows:

0xb13004680xb13004980x9f887280xb13004980xb13004780xb13004980xb11004880xb13004980xb13004880xb13004980xb13004980xb13004980x9f887380xb13004980x9f887480xb13004980xb11004780xb13004980xb11004980xb13004980xb11004680xb13004980xb11004a80xb11004a8

It is clear that our code cannot withstand the scrutiny of multithreading.

What to do? Locking So we improved again:

classsingleton{ Public:    StaticSingleton *getinstance () {mutex_.Lock(); if(Pinstance_ = = NULL)//Switching of ThreadsPinstance_ =NewSingleton;        Mutex_.unlock (); returnPinstance_; }Private: Singleton () {}StaticSingleton *Pinstance_; Staticmutexlock mutex_;}; Singleton*singleton::p Instance_ =NULL; Mutexlock singleton::mutex_;

At this point the test, no problem.

However, the mutex can greatly reduce the concurrency of the system, because each call to lock, equal to a group of people over the bridge.

I have written a test as follows:

classTestthread: Publicthread{ Public:    voidrun () {Const intKcount = +* +;  for(intIX =0; IX! = Kcount; ++ix) {singleton::getinstance (); }    }};intMainintargcChar Const*argv[]) {    //Singleton S; ERRORint64_t StartTime=Getutime (); Const intKsize = -;    Testthread Threads[ksize];  for(intIX =0; IX! = ksize; ++ix) {Threads[ix].start (); }     for(intIX =0; IX! = ksize; ++ix) {threads[ix].join (); } int64_t endTime=Getutime (); int64_t Difftime= EndTime-StartTime; cout<<"Cost :"<< Difftime/ +<<"Ms"<<Endl; return 0;}

100 threads are opened, each calling 1M times getinstance, where getutime is defined as follows:

int64_t Getutime () {    struct  timeval TV;    :: memset (0sizeof  TV);     if (Gettimeofday (&TV, NULL) = =-1)    {        perror ("gettimeofday");        Exit (exit_failure);    }     = tv.tv_usec;      +  + ;     return Current ;}

The result of the operation is:

6914 ms

Dual lock mode is used

The above test, we still can't see the performance problem, I improved the code again:

classsingleton{ Public:    StaticSingleton *getinstance () {if(Pinstance_ = =NULL) {mutex_.Lock(); if(Pinstance_ = = NULL)//Switching of ThreadsPinstance_ =NewSingleton;        Mutex_.unlock (); }                returnPinstance_; }Private: Singleton () {}StaticSingleton *Pinstance_; Staticmutexlock mutex_;}; Singleton*singleton::p Instance_ =NULL; Mutexlock singleton::mutex_;

As you can see, I used the double check mode in GetInstance, where is the advantage of this code?

The internal use of mutexes, the code is reliable anyway

New after the first instance, each subsequent thread accesses the outermost if judgment to return directly , without the overhead of locking

I run the test again (the test code does not change) and the results are as follows:

438 ms

Aha, more than 10 times times the performance gap, it can be seen that our improvements are effective, only three lines of code, but brought more than 10 times times the efficiency of the increase!

End

This method of writing became DCLP (double-check-locking-pattern) mode, which was once thought to be absolutely correct, but later it was pointed out that in some cases this approach would be executed in a random order, so refer to Scott's C + + and the Perils of double-checked Locking-scott Meyer

C++singleton's DCLP (double lock) implementation and performance evaluation

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.