栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++学习日记13——多线程【下】

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++学习日记13——多线程【下】

学习视频链接

c++11并发与多线程视频课程_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Yb411L7ak?p=11&vd_source=0471cde1c644648fafd07b54e303c905

目录

五、单例设计模式共享数据分析

5.1 单例模式(懒汉式)

5.2 单例类和多线程结合

5.3 call_once


五、单例设计模式共享数据分析

5.1 单例模式(懒汉式)

1、单例模式

单例模式是,我们通过一个类,构造一个对象

我们的做法是让构造类是私有的,只能通过调用他的公开类来创建一个对象

2、代码实现

#include 
using namespace std;

class MyCAS  // 这是一个单例类
{
private:
	MyCAS() {}  // 私有化构造函数

private:
	static MyCAS* m_instance;  // 静态成员变量

public:
	static MyCAS* GetInstance() 
	{
		if (m_instance == NULL) 
		{
			m_instance = new MyCAS();
		}
		return m_instance;
	}

	void func()
	{
		cout << "测试用的函数" << endl;
	}
};

// 类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;

int main(void)
{
	MyCAS* p_a = MyCAS::GetInstance(); // 创建一个对象,返回该类对象指针
	MyCAS* p_b = MyCAS::GetInstance();
	cout << &p_a << " " << &(*p_a) << endl;
	cout << &p_b << " " << &(*p_b) << endl;
	if (p_a == p_b) {
		cout << "p_a == p_b" << endl;
	}
	else
	{
		cout << "p_a != p_b" << endl;
	}
	return 0;
}

3、程序结束时析构单例对象方法

#include 
using namespace std;

class MyCAS  // 这是一个单例类
{
private:
	MyCAS() {}  // 私有化构造函数

private:
	static MyCAS* m_instance;  // 静态成员变量

public:
	static MyCAS* GetInstance() 
	{
		if (m_instance == NULL) 
		{
			m_instance = new MyCAS();
		}
		return m_instance;
	}

	void func()
	{
		cout << "测试用的函数" << endl;
        static CGarhuishou cl;
	}

	class CGarhuishou  // 类中套类,用来释放对象
	{
    public:
		~CGarhuishou()
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};
};

// 类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;

int main(void)
{
	MyCAS* p_a = MyCAS::GetInstance(); // 创建一个对象,返回该类对象指针
	MyCAS* p_b = MyCAS::GetInstance();
	cout << &p_a << " " << &(*p_a) << endl;
	cout << &p_b << " " << &(*p_b) << endl;
}

 

5.2 单例类和多线程结合

1、理想情况下,在主线程中创建单例类,并且完成初始化,在子线程中只读

2、实际开发中,创建单例类可能在子线程中,有可能在多线程中同时被创建,现在就需要实现互斥

(1) 没有实现互斥的情况

因为处理器被争夺可能会产生两个类,就不是单例类了

#include 
#include 
using namespace std;

class MyCAS  // 这是一个单例类
{
private:
	MyCAS() {}  // 私有化构造函数

private:
	static MyCAS* m_instance;  // 静态成员变量

public:
	static MyCAS* GetInstance() 
	{
		if (m_instance == NULL) 
		{
			m_instance = new MyCAS();
            static CGarhuishou cl;
		}
		return m_instance;
	}

	void func()
	{
		cout << "测试用的函数" << endl;
	}

	class CGarhuishou  // 类中套类,用来释放对象
	{
    public:
		~CGarhuishou()
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};
};

// 类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;

// 线程入口函数
void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS* p_a = MyCAS::GetInstance();  // 这里可能会出现问题
	cout << "我的线程执行完毕了" << endl;
	return;
}

int main(void)
{
	std::thread mytobj1(mythread);
	std::thread mytobj2(mythread);
	mytobj1.join();
	mytobj2.join();
	return 0;
}

(2) 添加互斥

#include 
#include 
#include 
using namespace std;

std::mutex resource_mutex;

class MyCAS  // 这是一个单例类
{
private:
	MyCAS() {}  // 私有化构造函数

private:
	static MyCAS* m_instance;  // 静态成员变量

public:
	static MyCAS* GetInstance() 
	{
		std::unique_lock mymutex(resource_mutex);  // 自动加锁
		if (m_instance == NULL) 
		{
			m_instance = new MyCAS();
            static CGarhuishou cl;
		}
		return m_instance;
	}

	void func()
	{
		cout << "测试用的函数" << endl;
	}

	class CGarhuishou  // 类中套类,用来释放对象
	{
    public:
		~CGarhuishou()
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};
};

// 类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;

// 线程入口函数
void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS* p_a = MyCAS::GetInstance();  // 这里可能会出现问题
	cout << "我的线程执行完毕了" << endl;
	return;
}

int main(void)
{
	std::thread mytobj1(mythread);
	std::thread mytobj2(mythread);
	mytobj1.join();
	mytobj2.join();
	return 0;
}

(3) 因为上面的做法比较低效,每次都要上锁再检测是否==NULL,但是对于单例来说,只有第一次是需要检测的,所以改进成下面这种

    static MyCAS* GetInstance() 
	{
		if (m_instance == NULL) {
			std::unique_lock mymutex(resource_mutex);  // 自动加锁
			if (m_instance == NULL)
			{
				m_instance = new MyCAS();
                static CGarhuishou cl;
			}
			return m_instance;
		}
	}

5.3 call_once

1、简介

功能是保证函数 a() 只被调用一次

具备互斥量这种能力,而且比互斥量消耗的资源更少

需要与一个标记结合使用,这个标记 std::once_flag(这是一个结构),call_once 根据这个标记来决定对应的函数 a() 是否执行,调用 call_once() 成功后, call_once() 就把这个标记设置为一种已经调用的状态。后续对应的函数 a() 就不会再被执行了

2、代码

#include 
#include 
#include 
using namespace std;

std::mutex resource_mutex;
std::once_flag g_flag;  // 这个是系统定义的标记

class MyCAS  // 这是一个单例类
{
private:
	MyCAS() {}  // 私有化构造函数

	static void CreateInstance()  // 只被调用1次
	{
		m_instance = new MyCAS();
		static CGarhuishou cl;
	}

private:
	static MyCAS* m_instance;  // 静态成员变量

public:
	static MyCAS* GetInstance() 
	{
		if (m_instance == NULL) {
			std::call_once(g_flag, CreateInstance);  // 两个线程同时执行到这里,一个线程要等另外一个线程执行完CreateInstance
			return m_instance;
		}
	}

	void func()
	{
		cout << "测试用的函数" << endl;
	}

	class CGarhuishou  // 类中套类,用来释放对象
	{
	public:
		~CGarhuishou()
		{
			if (MyCAS::m_instance)
			{
				delete MyCAS::m_instance;
				MyCAS::m_instance = NULL;
			}
		}
	};
};

// 类静态变量初始化
MyCAS* MyCAS::m_instance = NULL;

// 线程入口函数
void mythread()
{
	cout << "我的线程开始执行了" << endl;
	MyCAS* p_a = MyCAS::GetInstance();  // 这里可能会出现问题
	cout << "我的线程执行完毕了" << endl;
	return;
}

int main(void)
{
	std::thread mytobj1(mythread);
	std::thread mytobj2(mythread);
	mytobj1.join();
	mytobj2.join();
	return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/971492.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号