C++ 并发与多线程(六)

单例设计模式共享数据分析、解决、call_once

一 设计模式大概谈

二 单例设计模式

该类只能创建一个对象

#include <stdio.h>
#include <iostream>
using namespace std;

class MyCAS
{
   private:
   MyCAS(){}
   static MyCAS* m_instance;
 public:
   static MyCAS* GetInstance()
   {

       if(m_instance == NULL)
       {
           m_instance = new MyCAS();
           //释放m_instance
           static CGarhuishou cl;
       }
       return m_instance;
   }
   class CGarhuishou
   {
   public:
       //类的析构函数
       ~CGarhuishou()
       {
           if(MyCAS::m_instance)
           {
               delete MyCAS::m_instance;
               MyCAS::m_instance = NULL;
           }

       }


   };
   void func()
   {
       cout<<"test"<<endl;
   }

};
//静态成员 类外初始化
MyCAS *MyCAS::m_instance = NULL;


int main(void)
{
    MyCAS *p_a = MyCAS::GetInstance(); //创建一个对象,返回该类对象的指针 而且只能创建一个
    MyCAS *p_b = MyCAS::GetInstance();  //返回唯一对象
    cout<<endl;

    return 0;
}

三 单例设计模式共享数据问题分析、解决

问题:需要在我们自己创建的线程(而不是主线程)中创建MyCAS,这个单例类的对象,这种线程可能不止一个(最少两个)。我们可能要面临GetInstance要互斥。

#include <stdio.h>
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

std::mutex resource_mutex;
class MyCAS
{
   private:
   MyCAS(){}
   static MyCAS* m_instance;
 public:
   static MyCAS* GetInstance()
   {
       //提高效率。
       //如果if(m_ instance=NULL)条件成立,则肯定表示m_ instance已经被new过了
       //b)如果if( m instance=NULL),不代表 m instance-定没被new过;
      if(m_instance == NULL) //双重锁定 双重检查
      {
        std::unique_lock<std::mutex>mymutex(resource_mutex);//自动加锁   
       {
           m_instance = new MyCAS();
           //释放m_instance
           static CGarhuishou cl;
       }
      }
       return m_instance;
   }
   class CGarhuishou
   {
   public:
       //类的析构函数
       ~CGarhuishou()
       {
           if(MyCAS::m_instance)
           {
               delete MyCAS::m_instance;
               MyCAS::m_instance = NULL;
           }
       }
   };
   void func()
   {
       cout<<"test"<<endl;
   }

};
//静态成员 类外初始化
MyCAS *MyCAS::m_instance = NULL;

//线程入口
void mythread()
{
    cout<<"my thread start"<<endl;
    MyCAS *p_a = MyCAS::GetInstance(); //这里可能出现问题 两个线程同时进入getInstance
    COUT<<"my thread over"<<endl;
    return;

}
int main(void)
{
//    MyCAS *p_a = MyCAS::GetInstance(); //创建一个对象,返回该类对象的指针 而且只能创建一个
//    p_a->func();
//    cout<<endl;
    std::thread myobj(mythread);
    std::thread myobj1(mythread);
    //这两个线程虽然是同一个入口函数,但是由于是两个线程,所以这里会出现两条通路同时执行getinstance
    //会到此m_instance被new多次

    return 0;
}

四 std::call_once()

该函数的第二个参数是一个函数名a(),call_once功能保证a函数被调用一次。
具备互斥量的能力,而且效率比互斥量消耗的资源更少
call_once需要与一个标记结合使用,这个标记std::once_flag,该标记其实是一个结构
call_once就是通过这个标记来决定对应的函数a是否执行,调用call_once成功后,call_once就把这个标志置位已调用状态。a函数不会再执行。

#include <stdio.h>
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

std::mutex resource_mutex;
std::once_flag g_flag;
class MyCAS
{
public:
    static void CreateInstance() //只被调用一次
    {
        std::chrono::milliseconds dura(20000);//休息20s
        std::this_thread::sleep_for(dura);
        cout<<"CreateInstance creating"<<endl;
        m_instance = new MyCAS();
        //释放m_instance
        static CGarhuishou cl;
    }
   private:
   MyCAS(){}
   static MyCAS* m_instance;
 public:

   static MyCAS* GetInstance()
   {
//       //提高效率。
//       //如果if(m_ instance=NULL)条件成立,则肯定表示m_ instance已经被new过了
//       //b)如果if( m instance=NULL),不代表 m instance-定没被new过;
//      if(m_instance == NULL) //双重锁定 双重检查
//      {
//        std::unique_lock<std::mutex>mymutex(resource_mutex);//自动加锁
//       {
//           m_instance = new MyCAS();
//           //释放m_instance
//           static CGarhuishou cl;
//       }
//      }
       std::call_once(g_flag,CreateInstance);  //两个线程同时执行到这个,则只能有一个被执行,且被卡住。
        cout<<"call_once over"<<endl;
       return m_instance;
   }
   class CGarhuishou
   {
   public:
       //类的析构函数
       ~CGarhuishou()
       {
           if(MyCAS::m_instance)
           {
               delete MyCAS::m_instance;
               MyCAS::m_instance = NULL;
           }
       }
   };
   void func()
   {
       cout<<"test"<<endl;
   }

};
//静态成员 类外初始化
MyCAS *MyCAS::m_instance = NULL;

//线程入口
void mythread()
{
    cout<<"my thread start"<<endl;
    MyCAS *p_a = MyCAS::GetInstance(); //这里可能出现问题 两个线程同时进入getInstance
    cout<<"my thread over"<<endl;
    return;

}
int main(void)
{
//    MyCAS *p_a = MyCAS::GetInstance(); //创建一个对象,返回该类对象的指针 而且只能创建一个
//    p_a->func();
//    cout<<endl;
    std::thread myobj(mythread);
    std::thread myobj1(mythread);
    //这两个线程虽然是同一个入口函数,但是由于是两个线程,所以这里会出现两条通路同时执行getinstance
    //会到此m_instance被new多次

    return 0;
}

CreateInstance creating只被打印一次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Michael.Scofield

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值