c++11 多线程使用

文章目录

    • 创建线程
    • 异常导致死锁
    • 实现两个线程交互的打印奇数和偶数(面试题)

创建线程

1.创建线程的方式:

  • 1.拷贝构造禁止了
  • 2.允许移动构造
  • 3.无参构造后我们可以对对象进行赋值操作
  • 4.传递可调用对象(例如包装器,泛函数,lambda,普通函数,静态成员函数) + 参数列表 进行创建
    在这里插入图片描述

2.样例展示

  1. lambda 创建方式
#include<iostream>
#include<thread>
#include<mutex>
#include <condition_variable>
#include<vector>
#include<atomic>
using namespace std;
int main()
{
	mutex mtx;
	int x = 0;
	int n = 10;
	int m;
	cin >> m;

	vector<thread> v(m);
	//v.resize(m);

	for (int i = 0; i < m; ++i)
	{
		// 移动赋值给vector中线程对象
		v[i] = thread([&](){
			for (int i = 0; i < n; ++i)
			{
				mtx.lock();

				cout << this_thread::get_id() << ":" << i << endl;
				std::this_thread::sleep_for(std::chrono::milliseconds(100));
				++x;

				mtx.unlock();
			}
		});
	}

	for (auto& t : v)
	{
		t.join();
	}

	cout << x << endl;

	return 0;
}

2.普通函数和function包装器 创建方式

#include <condition_variable>
#include<vector>
#include<atomic>
#include<functional>
using namespace std;

void Print(int n, int& x, mutex& mtx)
{
	for (int i = 0; i < n; ++i)
	{
		mtx.lock();

		cout <<this_thread::get_id()<<":"<<i << endl;
		std::this_thread::sleep_for(std::chrono::milliseconds(100));
		++x;

		mtx.unlock();
	}

}

class A
{
public:
	static void Print(int n, int& x,mutex& mtx)
	{
		for (int i = 0; i < n; ++i)
		{
			mtx.lock();

			cout << this_thread::get_id() << ":" << i << endl;
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
			++x;

			mtx.unlock();
		}

	}
};
int main()
{

	mutex m;
	int count = 0;
	function<void(int,int&,mutex&)> f1 = A::Print;
	thread t1(f1, 10, ref(count), ref(m));
	thread t2(f1, 10, ref(count), ref(m));
	//thread t1(&A::Print, 10, ref(count), ref(m));
	//thread t2(Print, 10, ref(count), ref(m));
	
	
	//&A::Print(10, ref(count), ref(m))//errer 因为地址是1 是错的
	t1.join();
	t2.join();
	cout << count << endl;

	return 0;
}

注意事项:
线程函数的传参都是拷贝,例如参数是引用类型,也是会拷贝传值的,原因是与底层实现有关(创建线程时参数首先传递给构造函数再传递给线程函数这个过程里出问题了) – 解决方案 “ref(引用对象)” 意思是强制以左值引用去传递

异常导致死锁

1.如何导致死锁


int main()
{
	mutex mtx;
	atomic<int> x = 0;
	//int x = 0;
	int n = 100;
	int m;
	cin >> m;

	vector<thread> v(m);
	for (int i = 0; i < m; ++i)
	{
		// 移动赋值给vector中线程对象
		v[i] = thread([&](){
			for (int i = 0; i < n; ++i)
			{
				mtx.lock();

				// 如果存在抛异常就死锁了,解决办法:我们使用try catch进行捕获
				try {
					cout << this_thread::get_id() << ":" << i << endl;
					std::this_thread::sleep_for(std::chrono::milliseconds(100));
				}
				catch (...)
				{
					mtx.unlock();
					throw;
				}

				mtx.unlock();

		
			std::this_thread::sleep_for(std::chrono::milliseconds(100));
			}
		});
	}

	for (auto& t : v)
	{
		t.join();
	}

	cout << x << endl;

	return 0;
}

2.智能锁
智能锁像智能指针一样RALL机制,管理的资源声明周期随对象释放资源
不过c++库已经给我们实现了Lock guard类
Lock guard类通过RAII的方式对互斥锁进行了封装,在构造函数中进行加锁,在析构函数中自动解锁
如下模拟实现Lock guard类:

// RAII
template<class Lock>
class LockGuard
{
public:
	LockGuard(Lock& lk)
		:_lock(lk)
	{
		_lock.lock();
		cout << "thread:" << this_thread::get_id() << "加锁" << endl;
	}

	~LockGuard()
	{
		cout << "thread:" << this_thread::get_id() << "解锁" << endl << endl;
		_lock.unlock();
	}
private:
	Lock& _lock;
};
int main()
{
	mutex mtx;
	atomic<int> x = 0;
	//int x = 0;
	int n = 100;
	int m;
	cin >> m;

	vector<thread> v(m);
	for (int i = 0; i < m; ++i)
	{
		// 移动赋值给vector中线程对象
		v[i] = thread([&](){
			for (int i = 0; i < n; ++i)
			{
				{
					// 11:54继续
					lock_guard<mutex> lk(mtx);
					// 如果存在抛异常就死锁了
					cout << this_thread::get_id() << ":" << i << endl;
				}

				std::this_thread::sleep_for(std::chrono::milliseconds(100));
			}
		});
	}

	for (auto& t : v)
	{
		t.join();
	}

	cout << x << endl;

	return 0;
}

实现两个线程交互的打印奇数和偶数(面试题)

考察条件变量的使用,跟wait()与POSIX库用法差不多,都是需要循环检测条件是否满足

//方法一:不确定是否正确


// 实现两个线程交互的打印奇数和偶数
// 两个线程交错打印1-100,一个打印奇数,一个打印偶数
//int main()
//{
//	int i = 0;
//	int n = 100;
//
//	thread t1([&](){
//		while (i < n)
//		{
//			while (i % 2 != 0)
//			{
//				this_thread::yield();
//			}
//
//			cout <<this_thread::get_id()<<":"<<i << endl;
//			i += 1;
//		}
//	});
//
//
//	thread t2([&](){
//		while(i < n)
//		{
//			while (i % 2 == 0)
//			{
//				this_thread::yield();
//			}
//
//			cout << this_thread::get_id() << ":" << i << endl;
//			i += 1;
//		}
//	});
//
//	t1.join();
//	t2.join();
//
//	return 0;
//}

//方法二

int main()
{
	int i = 0;
	int n = 100;
	mutex mtx;
	condition_variable odd;//满足i为奇数
	condition_variable even;//满足i为偶数

	thread t1([&]() {

		while (i < n)
		{
			unique_lock<mutex> lock(mtx);
			//此时i为奇数才需要等待
			even.wait(lock, [&]()->bool{
				return i%2 == 0;
				});

			cout << this_thread::get_id() << ":偶数:" << i << endl;
			i++;
			odd.notify_one();
		}
		});

	thread t2([&]() {

		while (i < n)
		{
			unique_lock<mutex> lock(mtx);
			odd.wait(lock, [&]()->bool {
				return i % 2 != 0;
				});

			cout << this_thread::get_id() << ":奇数:" << i << endl;
			i++;
			even.notify_one();
		}
		});

	t1.join();
	t2.join();
	return 0;
}

//方法三

int main()
{
	int i = 0;
	int n = 100;
	mutex mtx;
	condition_variable cv;
	bool ready = true;

	// t1打印奇数
	thread t1([&](){
		while (i < n)
		{
			{
				unique_lock<mutex> lock(mtx);
				cv.wait(lock, [&ready](){return !ready; });

				cout << "t1--" << this_thread::get_id() << ":" << i << endl;
				i += 1;

				ready = true;

				cv.notify_one();
			}

			//this_thread::yield();
			this_thread::sleep_for(chrono::microseconds(100));
		}
	});

	// t2打印偶数
	thread t2([&]() {
		while (i < n)
		{
			unique_lock<mutex> lock(mtx);
			cv.wait(lock, [&ready](){return ready; });

			cout <<"t2--"<<this_thread::get_id() << ":" << i << endl;
			i += 1;
			ready = false;

			cv.notify_one();
		}
	});

	this_thread::sleep_for(chrono::seconds(3));

	cout << "t1:" << t1.get_id() << endl;
	cout << "t2:" << t2.get_id() << endl;

	t1.join();
	t2.join();

	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/4822.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第17章_触发器

第17章_触发器 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目前在某公…

JavaEE简单示例——SpringMVC的简单数据绑定

简单介绍&#xff1a; 在前面我们介绍过如何将我们自己创建的类变成一个servlet来处理用户发送的请求&#xff0c;但是在大多数的时候&#xff0c;我们在请求 的时候会携带一些参数&#xff0c;而我们现在就开始介绍我们如何在Java类中获取我们前端请求中携带的参数。首先&…

SpringBoot自定义注解+异步来实现日志管理

一、前言 我们在企业级的开发中&#xff0c;必不可少的是对日志的记录&#xff0c;实现有很多种方式&#xff0c;常见的就是基于AOP注解进行保存&#xff0c;同时考虑到程序的流畅和效率&#xff0c;我们可以使用异步进行保存&#xff01; 二、基础环境 1. 导入依赖 我这里…

C#,码海拾贝(06)——连分式(Continued Fraction)曲线插值算法,《C#数值计算算法编程》源代码升级改进版

一、连分式法 连分式法是一种有理函数逼近法&#xff0c;其基本出发点是&#xff1a;将原型展开成连分式&#xff0c;然后截取前面几个起主要作用的偏系数构成简化模型&#xff0c;连分式法计算简便&#xff0c;拟合精度较高&#xff0c;是一种很有效的传递函数简化法。 Cont…

【Spring Cloud Alibaba】5.创建服务消费者(Feign)

文章目录简介什么是 Feign开始搭建创建项目修改POM文件添加启动类创建 Feign 接口添加Controller添加配置文件启动项目测试访问Nacos访问接口测试负载均衡通过终端启动多个服务提供者实例简介 接下来我们创建一个服务消费者&#xff0c;通过Feign来进行与服务提供者交互&#…

KDZD程控超低频高压发生器

一、产品概述 本产品接合了现代数字变频技术&#xff0c;采用微机控制&#xff0c;升压、降压、测量、保护自动化。由于电子化&#xff0c;所以体积小重量轻、大屏幕液晶显示&#xff0c;清晰直观、且能显示输出波形、打印试验报告。 设计指标符合《电力设备专用测试仪器通用…

SSM—【笔记】1.1Spring

Spring好处 简化开发&#xff0c;降低企业级开发的复杂性框架整合&#xff0c;高效整合其他技术&#xff0c;提高企业级应用开发与运行效率 简化开发&#xff1a;1、IoC、2、AOP[2.1衍生出事务处理 ] 框架整合&#xff1a;MyBatis、Mybatis-plus、Struts、Struts2、Hibernat…

Android开发-Android常用组件-ToggleButton开关按钮 Switch开关

4.7 开关按钮ToggleButton和开关Switch 1.开关按钮ToggleButton 属性名 说明 android:disabledAlpha 设置按钮在禁用时的透明度 android:textOff 按钮没有被选中时显示的文字 android:textOn 按钮被选中时显示的文字 另外&#xff0c;除了这个我们还可以自己写个 selec…

Spring Cloud之一:注册与发现-Eureka工程的创建

系列目录&#xff08;持续更新。。。&#xff09; Spring Cloud&#xff1a;什么是微服务 Spring Cloud之一&#xff1a;注册与发现-Eureka工程的创建 Spring Cloud之二&#xff1a;服务提供者注册到Eureka Server Spring Cloud之三&#xff1a;Eureka Server添加认证 Spr…

SpringBoot(3)整合Mybatis

文章目录一、导入依赖二、编写配置文件三、在启动类上添加注解&#xff0c;表示mapper接口所在位置四、定义mapper接口五、定义mapper.xml映射文件六、service层七、controller层八、修改idea检查代码的严格程度一、导入依赖 <dependency><groupId>org.mybatis.spr…

华为OD机试题,用 Java 解【新员工座位安排系统】问题 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:新员工座位安排系统 题目 工位…

Ganache 安装

一. 下载Ganache Ganache下载链接 根据系统选择对应安装文件 或者brew安装 brew install --cask ganache 二.打开app 点击quickstart 点击save按钮&#xff0c;保存workspace&#xff0c;此时已启动对应端口为7545 三.打开truffle项目&#xff0c;设置配置文件 我已初始化…

华为OD机试题,用 Java 解【卡片组成的最大数字】问题 | 含解题说明

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典本篇题目:卡片组成的最大数字 题目 小组…

大数据分析工具Power BI(七):DAX使用场景及常用函数

DAX使用场景及常用函数 Power BI中DAX函数非常多,功能非常强大,下面结合一些实际场景来讲解DAX一些常用的函数,这些场景包含求和、计数、相除、排序、累计、环比、同比,为了更方便后续的可视化展示数据,我们新创建可视化展示的页面,创建一个新表存储后续展示的度量值,具…

iptables-ipset仅允许国内访问---端口白名单

前言&#xff1a;境外肉鸡攻击有点多&#xff0c;并业务无境外访问需求&#xff0c;IDC机房网络防火墙无法实现8K多条的china大陆地址导入&#xff1b;为实现仅china大陆地址访问&#xff0c;在业务端口如这里的80&#xff0c;使用iptables防火墙ipset过滤实现访问控制,对于访问…

HttpMessageConverter

基本介绍 我们进行Web开发&#xff0c;但是前端传入的 JSON 数据到底是如何被解析成 Java 对象作为 API入参的&#xff0c;后端返回的结果又是如何把 Java 对象解析成 返回给前端的&#xff0c;在整个数据流转的过程中&#xff0c;这些工作都是由谁来完成的呢&#xff1f; 从…

【UML建模】类图 类与接口表示方式、关系、基数详解

文章目录1.概述2.类的表示方式2.1.类与接口2.2.属性、方法、访问权限3.类之间的关系3.1.继承与实现3.2.关联、聚合、组合3.2.1.用代码表达关联关系3.2.2.用代码表达组合关系3.2.3.用代码表达聚合关系3.3.依赖3.3.1.依赖关系的代码实现4.基数5.总结1.概述 在我们的日常学习、工…

斐波拉契数列,有人买了一对小兔子,已知小兔子一个月后长成大兔子,大兔子每个月生一对小兔子,问:两年(24个月)之后,他一共有几对兔子。

[01]斐波拉契数列&#xff0c;有人买了一对小兔子&#xff0c;已知小兔子一个月后长成大兔子&#xff0c;大兔子每个月生一对小兔子&#xff0c;问:两年(24个月)之后&#xff0c;他一共有几对兔子。 第i月份大兔子小兔子总兔子1011210131124213532565387851381382192113341034…

Qt 正则表达式匹配失败的一个原因

在Qt中做正则表达式时&#xff0c;遇到一个很坑爹的问题&#xff0c;还是经验不足导致。 在正则表达式中&#xff0c;有很多需要元字符&#xff0c;是需要使用普通字符加转义符号搭配使用的。比如\w&#xff0c;\s。对于这类字符&#xff0c;在Qt中使用时&#xff0c;对\再次进…

Prometheus监控实战系列二十:监控Kubernetes集群(下)

本文承接上篇&#xff0c;在本篇中我们会讲解Prometheus如何应用基于Kubernetes的服务发现功能&#xff0c;检索目标信息并进行监控。 在监控策略上&#xff0c;我们将混合使用白盒监控与黑盒监控两种模式&#xff0c;建立起包括基础设施(Node)、应用容器&#xff08;Docker)、…