C++11新特性(5):多线程

news2024/11/18 9:23:21

学习C++11,根据网上资料的知识总结。

1. 线程创建

1.1 初始函数

#include <iostream>
#include <thread>
void myfunc(int &a) 
{
	cout << "a in myfunc:" << a++ << endl;
}

int main()
{
	int a = 1;

	std::thread mythread(myfunc, std::ref(a)); //带引用参数
	mythread.join();//阻塞

	cout << "a in main:" << a << endl;

	system("pause");
	return 0;
}

运行结果:

1.2 类对象

      需要重载()运算符,不然编译错误。

#include <iostream>
#include <thread>
class Task
{
	static int a;
private:
	int v;
public:
	Task() 
	{
		v = a++;
	}
public:
	void operator()()  //()重载
	{
		cout << "v:" << v<< endl;
	}
};
int Task::a = 0;
int main()
{
	for (int i = 0; i < 4; i++)
	{
		Task task;
		thread t(task);
		t.detach();
	}

	system("pause");
	return 0;
}

    运行结果不唯一,因为没有阻塞:

1.3 Lambda表达式

#include <thread>
int main()
{
	auto myLambda = [](int *a){
		for (int i = 0; i < 10; ++i)
		{
			cout << *a << endl;
		}
	};

	[myLambda]{
		int a = 10;
		thread mythread(myLambda,&a);
		mythread.detach();
	}();

	system("pause");
	return 0;
}

  运行结果:

        在Lambda线程中使用了局部变量a的指针,并且将该线程的运行方式设置为detach。这样,在lambda表达式执行结束后,变量a已经被销毁,但后台运行的线程仍然在使用已销毁变量a的指针,因此后面输出的值都是错误的。

        以detach方式执行线程时,最好将线程访问的局部数据复制到线程的空间(使用值传递),确保线程没有使用局部变量的引用或者指针。若一定要用,除非你能肯定该线程会在局部作用域结束前执行结束。使用join方式(阻塞)就不会出现这种问题,它会在作用域结束前完成退出。

1.4 std::async

      std::async是基于任务的,内部有调度器,比线程更高级别的抽象,可以看作是thread + packaged_task的封装。

原型async(std::launch::async | std::launch::deferred, f, args...)
第一个参数std::launch::deferred延迟调用,延迟到future对象调用get()或者wait()的时候才执行线程函数f
std::launch::async强制创建新线程,可能失败
std::launch::async |std::launch::deferred 默认值,系统会自行决定是异步(创建新线程)还是同步(不创建新线程)方式运行

       std::future与std::async配合使用。std::future提供了一个访问异步操作结果的机制,它和线程是一个级别的,属于低层次的对象。在它之上高一层的是std::packaged_task和std::promise,它们内部都有future以便访问异步操作结果。std::packaged_task包装的是一个异步操作(函数),std::promise包装的是一个值;都是为了方便异步操作的。

future_status三种状态
deferred异步操作还没开始
ready异步操作已经完成
timeout异步操作超时
获取结果三种方式
get等待异步操作结束并返回结果
wait等待异步操作结束,没有返回值
wait_for超时等待返回结果

代码示例:

#include <future>
#include <iostream>

using namespace std;

int main()
{
	future<int> future1 = async(launch::async, []() { return 6; });
	cout << future1.get() << endl;  //output: 6

	future<void> future2 = async(launch::async, []() {  cout << 8 << endl; });
	cout << "before wait" << endl;
	future2.wait(); //output: 8
	cout << "after wait" << endl;

	future<int> future3 = async(launch::async, []() {
		this_thread::sleep_for(chrono::seconds(3));
	return 9;
		});

	cout << "waiting...\n";
	future_status status;
	do {
		//查询状态
		status = future3.wait_for(chrono::seconds(1));

		if (status == future_status::deferred) {
			cout << "deferred\n";
		}
		else if (status == future_status::timeout) {
			cout << "timeout\n";
		}
		else if (status == future_status::ready) {
			cout << "ready!\n";
		}
	} while (status != future_status::ready);

	cout << "result is " << future3.get() << endl;
}

运行结果:

 before wait后面的数字8是future2输出的,还没来得及换行,说明确实是多线程在输出。

2. 线程同步

2.1 互斥锁

锁类型作用
std::mutex独占的互斥锁,不能递归使用
std::timed_mutex带超时的独占互斥锁,不能递归使用
std::recursive_mutex递归互斥锁,不带超时功能
std::recursive_timed_mutex带超时的递归互斥锁

       基本用法如下,建议使用C++11新增的模板类lock_guard,可以简化互斥锁 lock()和unlock()的写法,同时也更安全。还有一个模板类是unique_lock,基本用法和lock_guard一样,提供了更多构造函数,但更占资源。

#include <mutex>
std::mutex _mutex;
_mutex.lock();//加锁,阻塞
_mutex.unlock();//解锁
_mutex.try_lock();//尝试加锁,成功返回bool,失败返回false不阻塞
或
std::lock_guard<std::mutex> lock_mtx(_mutex);

2.2 条件变量

       条件变量需要和互斥量配合使用,属于另一种用于等待的同步机制,能阻塞一个或多个线程,直到收到另一个线程发出的通知或超时时,才能唤醒当前阻塞的线程。

使用
condition_variable配合 std::unique_lock<std::mutex> 进行 wait 操作,也就是阻塞线程的操作
conditon_variable_any2.1里的四种锁

2.3 自旋锁

       自旋锁是一种忙等待形式的锁,会在用户态不停的询问锁是否可以获取(获取不到一直循环),不会陷入到内核态中,所以更加高效,但是可能会对CPU资源造成浪费。C++11中没有直接提供自旋锁的实现,但提供了原子操作的实现,可以借助原子操作实现简单的自旋锁。

       相比互斥锁,自旋锁效率更高,但是长时间的自旋可能会使CPU得不到充分的应用。在临界区代码较少,执行速度快的时候应该使用自旋锁。而互斥锁不会浪费CPU资源,在无法获得锁时使线程阻塞,将CPU让给其他线程使用。对于等待资源时间较长的场景,应该用互斥锁。

代码示例:

#include <iostream>
#include <thread>
#include <atomic>

std::atomic_flag flag;
int a = 0;
void foo()
{
	for (int i = 0; i < 100; ++i)
	{
		while (flag.test_and_set())
		{

		}//加锁
		a += 1;
		flag.clear();//解锁
	}
}
int main()
{
	flag.clear();//初始化为clear状态

	std::thread t1(foo);
	std::thread t2(foo);
	t1.join();
	t2.join();
	std::cout << a << std::endl;
	return 0;
}

a. test_and_set:返回该atomic_flag对象当前状态,检查flag是否被设置,若被设置直接返回true,若没有设置则设置flag为true后再返回false。

b. clear:清除atomic_flag对象的标志位,即设置atomic_flag的值为false。

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

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

相关文章

Solr框架 02.Solr操作(document操作和query查询)

菜单项目Documents使用办法 其中的document选项&#xff1a; 以XML格式举例 1新增/修改 当id不存在时新增&#xff0c;当id存在修改。 <doc> <field name"id">8</field> <field name"name">明天更大卖</field> <field n…

好处多多的数仓分层是怎么样子的呢?如何创建数仓分层,

一、创建数仓分层 数仓分层是结合对业务场景、实际数据、使用系统的综合分析&#xff0c;对数据模型进行的整体架构设计及层级划分。用于将不同用途的数据&#xff0c;归类划分至不同的分层&#xff0c;便于您更好地组织、管理、维护数据。本文为您介绍如何创建并管理数仓分层…

Nik Dfine 降噪滤镜

Nik Define 是 Nik Collection 中专门用于降噪的滤镜。 Nik Dfine 有三种降噪方式&#xff1a;自动、手动以及精细局部控制。 大部分照片的降噪&#xff0c;用自动模式就可以达到满意效果。 有所侧重的话&#xff0c;可考虑手动降噪或精细局部控制方式降噪。 返回 Ps 后&#x…

JMeter分布式压测,启动执行机器报错: Port already in use: 1099

Problem creating registry: java.rmi.server.ExportException: Port already in use: 1099; nested exception is: java.net.BindException: Address already in use (Bind failed) 当压测量大的时候我们有时候会失败&#xff0c;然后再接着压测&#xff0c;这样就容易造成端口…

vue3框架开发uniapp高仿度小满金融App项目

vue3框架开发uniapp高仿度小满金融App项目 心血来潮写了度小满前端项目使用vue3开发地址&#xff1a;度小满金融 下面是实现效果

Jenkins + Docker + Maven + Windows 一键部署 Spring Boot 程序到远程 Linux 服务器

Jenkins Docker Maven Windows 一键部署 Spring Boot 程序到远程 Linux 服务器 文章目录 Jenkins Docker Maven Windows 一键部署 Spring Boot 程序到远程 Linux 服务器一、准备1、环境2、基本流程准备步骤基本思路 3、相关命令4、Dockerfile 文件5、配置远程服务器、安装…

外贸网站推广怎么做?英文外贸网站推广的好处

外贸网站推广是在全球范围内宣传和促销公司的产品或服务&#xff0c;以吸引国际客户和拓展海外市场。 以下是一些常见的外贸网站推广策略和方法&#xff1a; 网站优化&#xff1a;确保你的网站在搜索引擎上获得良好的排名。使用关键词研究和优化技术来提高网站的可见性和搜索引…

PostgreSQL中HOT对cluster的作用

PG中cluster的作用是根据表的索引重新构建一张表&#xff0c;并且表根据该索引进行排序&#xff0c;索引必须提前建好。 注意&#xff1a;cluster操作加ACCESS EXCLUSIVE锁&#xff0c;会阻塞其它任何操作。 我们为什么要运行cluster? PG中的表是堆表&#xff0c;表中行的顺…

SpringMvc接收前端发送的api请求参数问题笔记

SpringMvc接收前端发送的api请求参数问题笔记 get请求参数字符串日期转date接收 需要使用DateTimeFormat注解&#xff0c;来接收前端传的 http://xx.xx.xxx/xsdc?start2023-07-01 15:12:13&end2023-07-02 15:00:00 这种日期参数&#xff1b; 这样获取日期数据就能直接取…

启动一个qemu虚拟机

安装qemu&#xff1a; 编译内核&#xff1a; 编译rootfs&#xff1b; 启动&#xff1a; qemu-system-x86_64 -kernel ./linux-4.14.320/arch/x86_64/boot/bzImage -hda ./busybox-1.36.1/rootfs.img -append "root/dev/sda consolettyS0" -nographic 效果图&am…

乐优购物车微服务过滤拦截器

4.1.2.配置公钥 leyou:jwt:pubKeyPath: D:/heima/rsa/rsa.pub # 公钥地址cookieName: LY_TOKEN # cookie的名称 4.1.3.加载公钥 代码&#xff1a; ConfigurationProperties(prefix "leyou.jwt") public class JwtProperties { ​private String pubKeyPath;// 公…

git远程库GitHub

首先&#xff0c;注册一个GitHub&#xff08;github.com&#xff09;帐号&#xff0c;免费获得Git远程仓库 由于本地Git仓库和GitHub仓库之间的传输是通过SSH加密的&#xff0c;所以&#xff0c;需要一点设置&#xff1a; 第1步&#xff1a;创建SSH Key。在用户主目录下&…

学习一波Java语言中的优先队列 PriorityQueue

目录 一、什么是优先队列 二、PriorityQueue 如何使用 三、优先队列的使用场景 一、什么是优先队列 优先队列是一种特殊的队列数据结构&#xff0c;它根据元素的优先级来确定元素的顺序。与普通队列不同的是&#xff0c;优先队列中的元素并不按照插入的先后顺序进行排列&am…

SpringBoot整合logback日志框架详解(提供Gitee源码)

前言&#xff1a;本篇博客主要介绍如何把主流的日志框架快速整合到目前的SpringBoot框架中&#xff0c;对六种日志等级进行介绍以及使用方法。 目录 一、日志级别 1、TRACE 2、DEBUG 3、INFO 4、WARN 5、ERROR 6、FATAL 二、导入pom.xml依赖 三、application.yml配置…

seatunnel-2.3.2 doris数据同步到hive(cdh-6.3.2)首次运行踩坑记录

seatunnel-2.3.2 doris数据同步到hive(cdh-6.3.2)首次运行报错解决&#xff0c;解决的报错如下&#xff1a; 1、java.lang.NoClassDefFoundError: org/apache/hadoop/hive/metastore/api/MetaException 2、java.lang.NoClassDefFoundError: org/apache/thrift/TBase 3、java.la…

arcgis的属性显示bug

arcgis中&#xff0c;右键图层属性可以查看图层的属性信息&#xff0c;比如坐标系、波段数、行列数等。 但是今天实验的时候发现&#xff0c;这个属性中显示的波段最大最小值并非真值。 该图层实际范围为&#xff1a;30~711。 在arcgis属性中&#xff0c;显示范围为0~651。 在…

常用傅里叶变换对 傅里叶变换性质

记录下常用的傅里叶变换对 1. 对称性 2. 尺度变化性 根据上述性质求解&#xff1a; 上述函数可以理解为&#xff0c;cos(wt)的振幅是随着f(t)变化的&#xff0c;这个叫做调幅&#xff08;幅度受到了调制&#xff09;&#xff0c;不过一般发射的时候&#xff0c;还会发个载波&am…

【SQL应知应会】行列转换(二)• MySQL版

欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享&#xff0c;与更多的人进行学习交流 本文收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习&#xff0c;有基础也有进阶&#xff0c;有MySQL也有Oracle 行列转换 • Mysql版 前言一、MySQL行列转换1.数据…

SATA 和 ESATA 数据线针脚定义

esata定义 eSATA provides a variant of SATA for external connectivity. It uses a more robust connector, longer shielded cables, and stricter electrical standards. The protocol and logical signaling are identical to internal SATA. eSATA was standardized in 2…

【企业架构框架】SOGAF 通用实体框架 (CoE)

Salesforce 运营、治理和架构框架 (SOGAF) 将 MIT-CISR 企业架构框架应用于 Salesforce 实施和程序。 介绍 为共同实体&#xff08;即卓越中心&#xff09;制定一个明确的定义是很棘手的。转换程序中的通用实体 (CoE) 有多种名称&#xff1a; “卓越中心”、“C4E”、“专业中心…