C++11 线程库—线程操作(更新中)

news2024/11/16 22:01:35

前言

在C++11推出线程库前,Windows和Linux操作系统的线程操作并不同,这就导致多线程程序无法跨平台,如果想要跨平台,会很麻烦并且容易出错。C++11推出的线程库就解决了这一问题。
因为在Windows和Linux操作系统中有一些独特的常量,宏,所以可以凭借这些判断当前运行的平台,然后C++11的线程库通过条件编译,和独特的常量完成了跨平台编码。这就是C++11线程库的重要意义

PS:本篇博客仅记录常用语法

文章目录

  • 前言
  • 线程操作
    • 1. thread类
      • (1). 构造函数—创建线程
      • (2). 析构函数—销毁线程
      • (3). 线程等待—回收资源
      • (4). 赋值重载
      • (6). id类
      • (6). 获取线程ID
      • (7). 线程分离
      • (8). 线程交换
    • 2. this_thread命名空间
      • (1). get_id
      • (2).yield
  • 结束语

在这里插入图片描述

C++文档链接:C plus plus
C++11线程库总共有这些操作

在这里插入图片描述

线程操作

首先,最简单的,我们先学习创建线程相关的操作。在thread这个头文件中
而在thread头文件中,有一个thread类this_thread命名空间
我们先来学习thread类的相关操作

在这里插入图片描述

1. thread类

thread类包装了线程的相关操作,如创建,等待,交换等

(1). 构造函数—创建线程

在这里插入图片描述

首先我们来看thread类的构造函数,也就是创建线程。

函数声明说明
thread( ) noexcept不会抛异常的无参构造
template<class Fn , class… Args> explicit thread( Fn&& fn,Args &&… args )支持列表初始化和可变参数初始化,不支持隐式类型转换的有参构造
thread(const thread&)=delete不支持拷贝构造
thread(thread&& x) noexcept移动构造

PS:
noexcept 在函数声明后作标识符,默认是noexcept(true),表示不会抛异常
class... Args 是可变参数模板
explicit 表示不支持隐式类型转换
=delete 在函数声明后,表示不会生成该函数

(2). 析构函数—销毁线程

析构函数其实就是封装了Linux中pthread_destroy,销毁线程,这样的系统调用接口

(3). 线程等待—回收资源

如果创建线程后,没有等待,直接析构函数销毁的话,会被强制报错,因为要确保线程资源的回收
在这里插入图片描述

线程库还提供判断一个线程是否join的函数—joinable

在这里插入图片描述
返回真表明该线程没有join等待

用法如下:

thread t1(....);
thread t2(....);

if(t1.joinable()) t1.join();
if(t2.joinable()) t2.join();

接下来,我们结合前三点简单展示线程创建—线程等待—线程销毁的过程

线程的启动函数目的是对全局变量x进行++,加到传参n
lambda表达式的使用可参看C++lambda表达式

代码如下:

#include<iostream>
#include<thread>

using namespace std;

int x = 0;

void test1()
{
	//创建第一个线程
	//启动函数使用lambda表达式
	thread t1([](int n) 
	{
		for (int i = 0; i < n; ++i)
		{
			++x;
		}
	},1000);//1000是传参给lambda表达式的
	
	//创建第二个线程
	thread t2([](int n)
	{
		for (int i = 0; i < n; ++i)
		{
			++x;
		}
	},1000);

	cout << "x = " << x << endl;
	//线程等待
	t1.join();
	t2.join();
	
	//出作用域后,调用析构函数销毁线程
}

int main()
{
	test1();
	return 0;
}

运行结果如下;

在这里插入图片描述

而如果没有join,则会直接报错
在这里插入图片描述

(4). 赋值重载

在这里插入图片描述

函数声明说明
thread& operator= (thread&& rhs) noexcept不会抛异常的移动构造
thread& operator= (const thread&) = delete不支持拷贝构造

我们用一个程序展示赋值重载的使用

#include<iostream>
#include<windows.h>
#include<thread>
using namespace std;
int x = 0;

void test()
{
	thread threads[5];

	for (int i = 0; i < 5; ++i)
	{
		//使用匿名对象赋值,移动构造
		threads[i] = thread([](int n) 
		{
			for (int j = 0; j < n; j++)
			{
				++x;
			}
		},(i+1)*100);
	}

	for (int i = 0; i < 5; ++i)
	{
		threads[i].join();
	}

	cout << "x = " << x << endl;
}

int main()
{
	test();

	return 0;
}

赋值重载不支持拷贝构造,但支持移动构造,所以不能接收左值,可以接收右值,所以意味着可以使用匿名对象
以上代码就是先实例化一个线程数组,然后使用匿名对象赋值,完成多线程操作。

(6). id类

id类是thread类的一个内部类,其作用是存储线程的一些属性,比如线程ID。同时其重载了各种运算符,作用于线程的比较

在这里插入图片描述

同时也有operator<<的重载,方便输出线程ID

在这里插入图片描述

(6). 获取线程ID

在这里插入图片描述

get_id返回一个id类,主要是直接cout输出线程ID

thread t1();
cout<<t1.get_id()<<endl;

但是此方法不常用,因为需要通过对象调用,而输出线程ID一般是在启动函数中使用,启动函数中无法通过对象调用,所以输出线程ID的常用方法是this_thread命名空间的get_id。我们稍后讲解

(7). 线程分离

线程分离的函数是detach。线程调用detach后会与创建他的线程分离,即不需要join等待
在这里插入图片描述

(8). 线程交换

在这里插入图片描述

第一个swap,是通过对象调用的,第二个是静态成员函数,通过类名可直接调用


2. this_thread命名空间

this_thread命名空间,提供了4个成员函数

在这里插入图片描述
因为thread类的成员函数无法在启动函数中调用,所以this_thread命名空间解决了这一问题

函数声明说明
get_id获取线程ID
yield让出时间片
sleep_until使线程休眠到一个时间点
sleep_for使线程休眠一段时间

(1). get_id

通过this_thread调用get_id,我们就可以在启动函数中,获取当前线程的ID了
在这里插入图片描述

需要注意的是,this_thread的get_id也是返回id类
在这里插入图片描述

(2).yield

yield是让出当前线程的时间片,需要注意的是,yield同Sleep一样,不会解锁,所以想通过yield实现多线程交替运行,需要在yield的上下解锁和加锁
切出时间片,操作系统会保存上下文,切回来时,直接从yield后开始运行

mutex.unlock();//解锁
this_thread::yield();//让出时间片
mutex.lock();//加锁

sleep_until和sleep_for的使用较为麻烦,后续补充

结束语

感谢你的阅读

如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。
在这里插入图片描述

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

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

相关文章

OpenGL 鼠标拾取模型

1.简介 在我们的场景中&#xff0c;使用鼠标光标点击或“挑选”一个3d对象是很有用的。一种方法是从鼠标投射3d光线&#xff0c;通过相机&#xff0c;进入场景&#xff0c;然后检查光线是否与任何物体相交。这通常被称为光线投射。 我们不是从局部空间中的网格开始&#xff0c…

gRPC 实践

RPC 包管理&#xff0c;1.12前&#xff1b;旧版本要设置GO111MODULEoff&#xff1b;查找gopath/src;goroot/src&#xff1b;几乎没有包管理&#xff1b; 新版本&#xff1b;go.mod&#xff1b; module xxx go version设置GO111MODULEon 是什么 远程过程调用&#xff1b; …

Windows页面置换算法与文件操作

实验一 一、实验内容或题目&#xff1a; 随机产生页面访问序列&#xff0c;并实现LRU, FIFO, OPT三种算法进行缺页比较 二、实验目的与要求&#xff1a; 1、编写程序&#xff0c;随机产生页面访问序列&#xff0c;并实现LRU, FIFO, OPT三种算法进行缺页比较。 2、理解三种算…

自监督学习简介

1.  自监督学习 自监督学习是可以看做是一种特殊的无监督学习的一个子类别&#xff08;但并非无监督学习&#xff09;&#xff0c;因为它利用了未标记的数据。 关键思想是让模型无需手动标签即可学习数据表示。一旦模型学会了如何表示数据&#xff0c;那么它就可以用较少量的…

liunx+docker+rabbitmq安装延迟队列插件

安装版本 rabbit: RabbitMQ 3.8.16 erlang: Erlang 23.3.2 rabbit: rabbitmq_delayed_message_exchange-3.8.9-0199d11c.ez 准备 1.rabbmitMQ 安装 docker pull rabbitmq 2.rabbmitMQ 启动 docker run -d --hostname my-rabbit --name rabbit -e RABBITMQ_DEFAULT_USER用户…

10 种分布式系统必备模式

在当今的技术领域中&#xff0c;分布式系统已成为许多大型应用程序和平台的核心。构建高性能、可伸缩和可靠的分布式系统是一个复杂的挑战&#xff0c;需要合理的架构设计和模式选择。本文将介绍10个必备的分布式系统模式&#xff0c;帮助您更好地理解和应用这些模式以提升系统…

pytorch笔记:RNN 系列

来自B站视频&#xff0c;API查阅&#xff0c;TORCH.NN RNN可以处理变长序列&#xff0c;是因为其每个时刻的参数是共享的RNN每算出一个时刻都可以输出&#xff0c;适合流式输出&#xff0c;但串行计算比较慢&#xff0c;无法获取太长的历史信息RNN 初始隐状态不提供默认是0&am…

一、枚举类型——用枚举实现状态机

枚举类型很适合用来实现状态机。状态机可以处于有限数量的特定状态。它们通常根据输入&#xff0c;从一个状态移动到下一个状态&#xff0c;但同时也会存在瞬态。当任务执行完毕后&#xff0c;状态机会立即跳出所有状态。 每个状态都有某些可接受的输入&#xff0c;不同的输入…

你应该知道的 Python 自动化脚本

概要 我们都有一些需要重复做的任务。幸运的是&#xff0c;我们可以将其中一些过程自动化&#xff0c;这样我们就可以专注于做其他真正需要精力和注意力的事情。 在这篇文章中&#xff0c;我们将谈论一些 Python 自动化脚本&#xff0c;你可以轻松地用它们来执行自动化任务。重…

巨星内马尔为孕期出轨道歉了!喊话女友:“我不能想象失去你”

近日&#xff0c;巴西球星内马尔在女友布鲁娜孕期出轨的传闻引起了社会广泛关注。 22日凌晨&#xff0c;内马尔在自己的社交媒体上发文回应并道歉&#xff0c;表示自己在球场内外都会犯错&#xff0c;但私生活的问题他会在家里解决。 他还重申了自己已经为犯下的错误和不必要的…

python爬虫_函数的使用

文章目录 ⭐前言⭐python函数&#x1f496; 参数传递—值&#x1f496; 参数传递—引用&#x1f496; 多参数(*)&#x1f496;lambda匿名函数 结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于python函数入门使用。 该系列文章&#xff1a; python爬虫_基本数…

【031】C++类和对象之运算符重载详解和代码实践(最全讲解)

C类和对象之运算符重载详解 引言一、运算符重载的基本概念1.1、可重载的运算符1.2、不可重载的运算符 二、重载 << 运算符&#xff08;全局函数实现&#xff09;三、重载 >> 运算符&#xff08;全局函数实现&#xff09;四、重载 运算符4.1、全局函数实现4.2、成员…

leetcode257. 二叉树的所有路径(java)

二叉树的所有路径 leetcode257. 二叉树的所有路径题目描述DFS深度优先遍历 二叉树专题 leetcode257. 二叉树的所有路径 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/binary-tree-paths 题目描述 给你一个二叉树的根节…

【系统开发】尚硅谷 - 谷粒商城项目笔记(十一):K8S

文章目录 K8s简介架构原理核心概念控制平面组件&#xff08;Control Plane Components&#xff09;kube-apiserveretcdkube-schedulerkube-controller-managercloud-controller-manager Node 组件kubeletkube-proxy容器运行时&#xff08;Container Runtime&#xff09; 插件&a…

Gee 项目复现

序言 复现&#xff1a;原链接 一个Web框架需要支持的功能&#xff0c; 路由&#xff0c;请求到响应函数的映射&#xff0c;支持动态路由如hello/:name,hello/*模板&#xff0c;使用内置模板引擎渲染机制。鉴权&#xff1a;分组插件&#xff1a;中间件 第一天 HTTP基础 启动…

基于边界点优化和多步路径规划的机器人自主探索

论文题目&#xff1a;Autonomous Robotic Exploration Based on Frontier Point Optimization and Multistep Path Planning 中文题目&#xff1a;基于边界点优化和多步路径规划的机器人自主探索 作者&#xff1a;Baofu Fang &#xff1b;Jianfeng Ding ; Zaijun Wang 作者机…

5.5.2 IPv6数据报格式

5.5.2 IPv6数据报格式 首先我们来回忆一下IPv4数据报首部格式&#xff08;5.2.3 IP数据报&#xff08;一&#xff09;IP数据报的格式&#xff09;&#xff0c;包括20个字节的固定部分和长度可变的选项部分&#xff0c;如图 红色方框标注的是在IPv6中会消失的字段&#xff0c;椭…

小白也会的------新建Python虚拟环境,查看该虚拟环境的路径,将该虚拟环境的所有库和版本号导出到一个 requirements.txt 文件中

我的目录标题 1、新建Python虚拟环境2、查看该虚拟环境的路径3、将该虚拟环境的所有库和版本号导出到一个 requirements.txt 文件中4、如果你只需要将当前虚拟环境中安装的所有库和版本号导出到一个 requirements.txt 文件中&#xff0c;而不需要包括每个库的来源&#xff0c;可…

KMP算法基础

前言 KMP算法是我们数据结构串中最难也是最重要的算法。难是因为KMP算法的代码很优美简洁干练&#xff0c;但里面包含着非常深的思维。真正理解代码的人可以说对KMP算法的了解已经相当深入了。而且这个算法的不少东西的确不容易讲懂&#xff0c;很多正规的书本把概念一摆出直接…

C++——命名空间(namespace)

目录 1. C语言命名冲突 2. 命名空间定义 3. 命名空间使用 可能大家在看别人写的C代码中&#xff0c;在一开始会包这个头文件&#xff1a;#include<iostream> 这个头文件等价于我们在C语言学习到的#include<stdio.h>&#xff0c;它是用来跟我们的控制台输入和输出…