C++11并发与多线程笔记(10) future其他成员函数、shared_future、atomic

news2024/9/26 1:24:40

C++11并发与多线程笔记(10) future其他成员函数、shared_future、atomic

  • 1、std::future 的成员函数
    • 1.1 std::future_status
  • 2、std::shared_future:也是个类模板
  • 3、std::atomic原子操作
    • 3.1 原子操作概念引出范例:
    • 3.2 基本的std::atomic用法范例

1、std::future 的成员函数

1.1 std::future_status

status = result.wait_for(std::chrono::seconds(几秒));

卡住当前流程,等待std::async()的异步任务运行一段时间,然后返回其状态std::future_status。如果std::async()的参数是std::launch::deferred(延迟执行),则不会卡住主流程。
std::future_status是枚举类型,表示异步任务的执行状态。类型的取值有

  • std::future_status::timeout
  • std::future_status::ready
  • std::future_status::deferred
#include <iostream>
#include <future>
using namespace std;
 
int mythread() {
	cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);
	cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
	return 5;
}

int main() {
	cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
	std::future<int> result = std::async(mythread);
	cout << "continue........" << endl;
	//cout << result1.get() << endl; //卡在这里等待mythread()执行完毕,拿到结果
	//等待6秒
    std::future_status status = result.wait_for(std::chrono::seconds(6));
	if (status == std::future_status::timeout) {
		//超时:表示线程还没有执行完
		cout << "超时了,线程还没有执行完" << endl;
	}else if(status==std::future_status::ready){
		cout<<"线程成功执行完毕,返回"<<endl;
		cout<<result.get()<,endl;
	}else if(status==std::future_status::deferred){
		//如果async的第一个参数被设置为std::launch::deferred,则本条件成立
		cout<<"线程被延迟!!"<<endl;//mythread在主线程执行
		cout<<result.get()<,endl;
	}
	cout<<"I love China!"<<endl;
	return 0;
}

在这里插入图片描述

注意get()只能使用一次。get()函数的设计是一个移动语义,相当于将result中的值移动了,再次get就报告了异常。

2、std::shared_future:也是个类模板

  • std::future的 get() 成员函数是转移数据
  • std::shared_future 的 get()成员函数是复制数据
#include <thread>
#include <iostream>
#include <future>
using namespace std;
 
int mythread() {
	cout << "mythread() start" << "threadid = " << std::this_thread::get_id() << endl;
	std::chrono::milliseconds dura(5000);
	std::this_thread::sleep_for(dura);
	cout << "mythread() end" << "threadid = " << std::this_thread::get_id() << endl;
	return 5;
}

void mythread2(std::shared_future<int> &tmpf){//此时使用shared_future
	cout<<"mythread2() start"<<"threadid="<<std::this_thread::get_id()<<endl;
	auto result=tmpf.get();//可以get多次
	cout<<"mythread2 result="<<result<,endl;
}
int main() {
	cout << "main" << "threadid = " << std::this_thread::get_id() << endl;
	std::packaged_task<int()> mypt(mythread);
	std::thread t1(std::ref(mypt));
	std::future<int> result = mypt.get_future();
	
	bool ifcanget = result.valid(); //判断future中的值是不是一个有效值
	//方法1
	std::shared_future<int> result_s(result.share()); //执行完毕后result_s里有值,而result里空了
	//方法2
	//std::shared_future<int> result_s(std::move(result));
	//方法3
    //通过get_future返回值直接构造一个shared_future对象
    //std::shared_future<int> result_s(mypt.get_future());
    t1.join();
	
	auto myresult1 = result_s.get();
	auto myresult2 = result_s.get();
 	
 	std:: thread t2(mythread2,std::ref(result_s));
 	t2.join();//等待线程执行完毕
	cout << "good luck" << endl;
	return 0;
}

3、std::atomic原子操作

3.1 原子操作概念引出范例:

互斥量:多线程编程中用于保护共享数据:先锁住-> 操作共享数据->解锁。

两个线程,对一个变量进行操作,一个线程这个变量的值,一个线程往这个变量中值。

(1) 即使是一个简单变量的读取和写入操作,如果不加锁,也有可能会导致读写值混乱(一条C++语句会被拆成3、4条汇编语句来执行,所以仍然有可能混乱)

#include <iostream>
#include <thread>
using namespace std;
int g_count = 0;
 
void mythread1() {
	for (int i = 0; i < 1000000; i++) {
		g_count++;
	}
	return;
}
 
int main() {
	std::thread t1(mythread1);
	std::thread t2(mythread1);
	t1.join();
	t2.join();
	cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
}

在这里插入图片描述
原因:一条C++语句会被拆成3、4条汇编语句,线程上下文切换就有可能打乱。

(2)如果使用互斥量 mutex解决这个问题

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int g_count = 0;
std::mutex mymutex;

void mythread1() {
	for (int i = 0; i < 1000000; i++) {
		std::unique_lock<std::mutex> u1(mymutex);
		g_count++;
	}
}
 
 
int main() {
	std::thread t1(mythread1);
	std::thread t2(mythread1);
	t1.join();
	t2.join();
	cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
}

在这里插入图片描述

3.2 基本的std::atomic用法范例

可以把原子操作理解成一种:不需要用到互斥量加锁(无锁)技术的多线程并发编程方式。

原子操作:在多线程中不会被打断的程序执行片段
从效率上来说,原子操作要比互斥量的方式效率要

互斥量的加锁一般是针对一个代码段,而原子操作针对的一般都是一个变量

原子操作,一般都是指“不可分割的操作”;也就是说这种操作状态要么是完成的,要么是没完成的,不可能出现半完成状态。

std::atomic来代表原子操作,是个类模板。其实std::atomic是用来封装某个类型的值的

案例1:

#include <iostream>
#include <thread>
#include <atomic> //添加#include <atomic>头文件
using namespace std;
std::atomic<int> g_count = 0; //封装了一个类型为int的 对象(值)

void mythread1() {
	for (int i = 0; i < 1000000; i++) {
		g_count++;//对应的的操作是原子操作(不会被打断)
	}
}
 
int main() {
	std::thread t1(mythread1);
	std::thread t2(mythread1);
	t1.join();
	t2.join();
	cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
}

在这里插入图片描述
案例2(bool 案例):

#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
std::atomic<bool> g_ifEnd = false; //封装了一个类型为bool的 对象(值)
 
void mythread() {
	std::chrono::milliseconds dura(1000);//1s
	while (g_ifEnd == false) {
	//系统没要求线程退出,所以本线程可以干自己想干的事情
		cout << "thread id = " << std::this_thread::get_id() << "运行中" << endl;
		std::this_thread::sleep_for(dura);
	}
	cout << "thread id = " << std::this_thread::get_id() << "运行结束" << endl;
}
 
int main() {
	std::thread t1(mythread);
	std::thread t2(mythread);
	std::chrono::milliseconds dura(5000);//5s
	std::this_thread::sleep_for(dura);
	g_ifEnd = true;//对原子对象的写操性,让线程自行运行结束;
	t1.join();
	t2.join();
	cout << "程序执行完毕" << endl;
}

在这里插入图片描述
总结:

  1. 原子操作一般用于计数或者统计(如累计发送多少个数据包,累计接收到了多少个数据包),多个线程一起统计,这种情况如果不使用原子操作会导致统计发生混乱。

  2. 写商业代码时,如果不确定结果的影响,最好自己先写一小段代码调试。或者不要使用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CTFhub-sql注入-绕过空格过滤

常用绕过空格过滤的方法&#xff1a; /**/、()、%0a 1.判断是否存在sqli注入 1 1/**/union/**/select/**/11 1/**/union/**/select/**/12 如果1/**/union/**/select/**/11的显示结果与1/**/union/**/select/**/12的显示结果不一样&#xff0c; 与1的结果一样说明存在注入…

JMeter中利用Jython运行Python代码

介绍 Jython是Python和Java的结合。Jython语法和Python一样&#xff0c;不但可以使用Python的库&#xff0c;而且还可以调用Java的库。结合了Python和Java的优点&#xff0c;也就是说Jython既有动态语言的灵活性&#xff0c;又可以用静态语言的强大的类库。其实&#xff0c;我…

Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)

文章目录 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)前情提要客户端部分 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三) 前情提要 单例泛型类 using System.Collections; using System.Collections.Generic; …

Android6:片段和导航

创建项目Secret Message strings.xml <resources><string name"app_name">Secret Message</string><string name"welcome_text">Welcome to the Secret Message app!Use this app to encrypt a secret message.Click on the Star…

周末时间在家重新做了一个电脑系统,手艺没有丢!!!

有个朋友的电脑抱怨自己太卡&#xff0c;有缘见过几次他的电脑&#xff0c;确实哦&#xff0c;10年的老笔记本了&#xff0c;关键还是日本买的东芝t552,配置4G500G&#xff0c;昨天晚上朋友提过来的时候&#xff0c;大吃已经&#xff0c;还以为是电磁炉呢。看下面的图片就知道了…

平方数之和(力扣)双指针 JAVA

给定一个非负整数 c &#xff0c;你要判断是否存在两个整数 a 和 b&#xff0c;使得 a&#xff3e;2 b&#xff3e;2 c 。 示例 1&#xff1a; 输入&#xff1a;c 5 输出&#xff1a;true 解释&#xff1a;1 * 1 2 * 2 5 示例 2&#xff1a; 输入&#xff1a;c 3 输出&am…

Linux系统调试——核心转储(core dump)

本篇讲解Linux应用程序发生Segmentation fault段错误时&#xff0c;如何利用core dump文件定位错误。 核心转储 在 Linux 系统中&#xff0c;常将“主内存”称为核心(core)&#xff0c;而核心映像(core image) 就是 “进程”(process)执行当时的内存内容。 当进程发生错误或…

计算机竞赛 图像识别-人脸识别与疲劳检测 - python opencv

文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是…

LVS-DR模型实例

一、LVS-DR集群介绍 LVS-DR&#xff08;Linux Virtual Server Director Server&#xff09;工作模式&#xff0c;是生产环境中最常用的一 种工作模式。 1、LVS-DR 工作原理 LVS-DR 模式&#xff0c;Director Server 作为群集的访问入口&#xff0c;不作为网关使用&#xff0…

借助Midjourney创作龙九子图

&#xff08;本文阅读时间&#xff1a;5 分钟&#xff09; 《西游记》中有这么一段描写&#xff1a; 龙王道&#xff1a;“舍妹有九个儿子。那八个都是好的。第一个小黄龙&#xff0c;见居淮渎&#xff1b;第二个小骊龙&#xff0c;见住济渎&#xff1b;第三个青背龙&#xff0…

Linux 消息队列的创建与使用

消息队列的创建与使用 进程a发送一条消息&#xff0c;进程b读取消息。 a.c代码&#xff1a; b.c代码&#xff1a; 1.a进程创建向消息队列&#xff0c;并向消息队列中发送消息 运行a程序之前&#xff0c;当前系统中消息队列的数量为0&#xff1a; 运行一次a程序&#xff0c;消…

JVM——StringTable面试案例+垃圾回收+性能调优+直接内存

JVM——引言JVM内存结构_北岭山脚鼠鼠的博客-CSDN博客 书接上回内存结构——方法区。 这里常量池是运行时常量池。 方法区 面试题 intern()方法 intern() 方法用于在运行时将字符串添加到内部的字符串池stringtable中&#xff0c;并返回字符串池stringtable中的引用。 返…

【rust/egui】(三)看看template的app.rs:序列化、持久化存储

说在前面 rust新手&#xff0c;egui没啥找到啥教程&#xff0c;这里自己记录下学习过程环境&#xff1a;windows11 22H2rust版本&#xff1a;rustc 1.71.1egui版本&#xff1a;0.22.0eframe版本&#xff1a;0.22.0上一篇&#xff1a;这里 serde app.rs中首先定义了我们的Templ…

2023.8.19-2023.8.XX 周报【人脸3D+虚拟服装方向基础调研-Cycle Diffusion\Diffusion-GAN\】更新中

学习目标 1. 这篇是做diffusion和gan结合的&#xff0c;可以参照一下看看能不能做cyclegan的形式&#xff0c;同时也可以调研一下有没有人follow这篇论文做了类似cyclegan的事情 Diffusion-GAN论文精读https://arxiv.org/abs/2206.02262 2. https://arxiv.org/abs/2212.06…

python——json、字典的区别及相互转换方法

前言 json&#xff0c;是一种轻量级的数据交换格式&#xff0c;由JavaScript语言创建&#xff0c;广泛应用于网页数据交互&#xff0c;常见于爬虫和数据分析领域。 json格式简洁、结构清晰&#xff0c;存储格式为&#xff1a;键值对&#xff08;key:value&#xff09; 在pytho…

创作的1024天 分享月入5K的副业心得

机缘 今天早上醒来打开电脑&#xff0c;和往常一样点开csdn&#xff0c;看见有一封私信&#xff0c;原来是系统通知&#xff0c;今天是我成为创作者的1024天&#xff0c;那就趁着这个机会&#xff0c;分享一下目前我月入5K的副业心得。我是一个普通人&#xff0c;最初想成为创…

【100天精通python】Day41:python网络爬虫开发_爬虫基础入门

目录 专栏导读 1网络爬虫概述 1.1 工作原理 1.2 应用场景 1.3 爬虫策略 1.4 爬虫的挑战 2 网络爬虫开发 2.1 通用的网络爬虫基本流程 2.2 网络爬虫的常用技术 2.3 网络爬虫常用的第三方库 3 简单爬虫示例 专栏导读 专栏订阅地址&#xff1a;https://blog.csdn.net/…

提高 Snowflake 工作效率的 6 大工具

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 Snowflake 彻底改变了企业存储、处理和分析数据的方式&#xff0c;提供了无与伦比的灵活性、可扩展性和性能。但是&#xff0c;与任何强大的技术一样&#xff0c;要真正利用其潜力&#xff0c;必须拥有…

vsCode使用cuda

一、vsCode使用cuda 前情提要&#xff1a;配置好mingw&#xff1a; 1.安装cuda 参考&#xff1a; **CUDA Toolkit安装教程&#xff08;Windows&#xff09;&#xff1a;**https://blog.csdn.net/qq_42951560/article/details/116131410 2.在vscode中添加includePath c_cp…

VS2015打开Qt的pro项目文件 报错

QT报错&#xff1a;Project ERROR: msvc-version.conf loaded but QMAKE_MSC_VER isn‘t set 解决方法&#xff1a; 找到本机安装的QT路径&#xff0c;找到“msvc-version.conf”文件&#xff0c;用记事本打开&#xff0c; 在其中添加版本“QMAKE_MSC_VER 1900”保存即可。 …