天天看點

C++單例懶漢式和多線程問題(MUTEX 保護)

單例懶漢式和多線程問題

作為單例模式,是在整個程式運作期間隻會建立一份記憶體空間,為了達到這個目标

1、需要将構造函數設定為私有成員

2、需要一個私有的靜态指針指向自身

3、需要一個公有的靜态函數将這個上面的靜态指針露出來

如下的代碼就是一個懶漢式的單例

點選(此處)折疊或打開

#include<iostream>

using namespace std;

class single_ins

{

private:

    int a;

    int b;

    single_ins()

    {

        a= 0;

        b= 0;

    }

    static single_ins* myc;

public:

    void setval(const int& a,const int& b)

        this->a = a;

        this->b = b;

    void print()

      cout<<"a:"<<a<<endl;

      cout<<"b:"<<b<<endl;

    static single_ins* setp()

        //?

        if(myc == NULL)

        {

            myc = new single_ins;

        }

        return myc;

    static void pfree()

        if(myc != NULL)

            delete myc;

            myc = NULL;

};

//? init static value

single_ins* single_ins::myc = NULL;

//nit static value

//single_ins* single_ins::myc = new single_ins;

int main()

    single_ins* a = single_ins::setp();

    single_ins* b = single_ins::setp();

    a->setval(10,20);

    b->print();

    cout<<a<<" "<<b<<endl;

    single_ins::pfree();

}

但是上面的代碼有明顯的問題,就是遇到多線程的情況下,因為多個線程如果同僚建立記憶體,由于彼此之間

并不能及時檢查到記憶體已經配置設定,會配置設定多個記憶體,這個時候我們至少需要一個線程間同步手段來讓他們之間

串行的執行,這個時候就涉及到兩次檢查(double check)

如果沒有mutex保護就是下面這個程式:

#include <iostream>

#include <unistd.h>

//單列模式

        private:

                int a;

                int b;

                single_ins()

                {

                        cout<<"con begin\n";

                        a= 0;

                        b= 0;

                        sleep(10); //故意拖長構造函數執行時間,造成懶漢式多線程問題

                        cout<<"con end\n";

                }

                static single_ins* myc;//單例需要一個靜态指針

                static int cnt;//構造調用次數統計

        public:

                void setval(const int& a,const int& b)

                        this->a = a;

                        this->b = b;

                void print()

                        cout<<"a:"<<a<<endl;

                        cout<<"b:"<<b<<endl;

                        cout<<cnt<<endl;

                static single_ins* setp() //函數獲得指針值賦給靜态成員指針變量

                        //懶漢式

                        if(myc == NULL)

                        {

                                myc = new single_ins;

                                cnt++;

                        }

                        return myc;

                static void pfree()

                        if(myc != NULL)

                                delete myc;

                                myc = NULL;

//懶漢式 init static value

int single_ins::cnt = 0;

//餓漢試 init static value

/*

   懶漢式的問題在于多線程調用的時候會出現問題,很可能同時建立出多個記憶體空間,

   而不是單列了。

   */

void* main21(void* argc)

        single_ins* inp = (single_ins*)argc;

        inp = single_ins::setp();

        inp->setval(10,20);

        inp->print();

        cout<<inp<<"\n";

        return NULL;

int main(void)

        pthread_t tid;

        single_ins* a[3] = {NULL};

        void* tret[3] = {NULL};

        for(int i = 0 ; i<3; i++)

                pthread_create(&tid,NULL,main21,(void*)a[i]);

                //pthread_join(tid, &(tret[i]));

        sleep(50);

        single_ins::pfree();

會跑出結果

con begin

con end

a:10

b:20

1

0x7fc3880008c0

2

0x7fc3800008c0

3

0x7fc3840008c0

可以看到

0x7fc3880008c0 0x7fc3800008c0 0x7fc3840008c0

明顯是3個不同的記憶體空間 這就不對了,而且可以看到構造函數

調用了3次

為此我們使用mutex來保護臨時

如下:

 static single_ins* setp() //函數獲得指針值賦給靜态成員指針變量

 39         {

 40             //懶漢式

 41             if(myc == NULL)

 42             {

 43                 pthread_mutex_lock(&counter_mutex); //mutex 保護臨界區

 44                 if(myc == NULL) //兩次檢查

 45                 {

 46                     myc = new single_ins;                                                                                                                           

 47                     cnt++;

 48                 }

 49                 pthread_mutex_unlock(&counter_mutex); //mutex結束

 50             }

這樣代碼如下:

pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;

                                pthread_mutex_lock(&counter_mutex); //mutex 保護臨界區

                                if(myc == NULL) //兩次檢查

                                {

                                        myc = new single_ins;

                                        cnt++;

                                }

                                pthread_mutex_unlock(&counter_mutex); //mutex結束

跑出的結果如下:

a:10a:10

0x7f21f40008c0

現在就是正常的了。是以懶漢試單例遇到多線程一定要注意,餓漢試沒有問題。

當然這是一個小列子而已,線程安全是一個很大的話題,特别需要注意。

作者微信:

C++單例懶漢式和多線程問題(MUTEX 保護)

繼續閱讀