当前位置: 首页 > news >正文

C++11线程库

C++11线程库

本质是对不同平台的线程库进行封装。因为windows和linux下各有自己的接口,这使得代码的可移植性比较差。C++11中最重要的特性就是对线程进行支持了,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。要使用标准库中的线程,必须包含<thread>头文件。

thread类

函数名功能
thread()构造一个线程对象,没有关联线程函数,即没有启动任何线程
thread(fn, args1, args2…)构造一个线程对象,并关联线程函数fn,argsx为线程函数的参数
get_id()获取线程id
joinable()线程是否还在执行,joinable表示的是一个正在执行中的线程
join()主线程调用该函数后会阻塞等待另一个线程返回
detach()在创建线程对象后马上调用,用于把被创建线程与线程对象分离开,分离的线程变为后台线程,创建的线程的"死活"就与主线程无关

this_thread命名空间

get_id是需要对象去调用的函数,当成成员函数不太好用,故可写为std::this_thread::get_id()直接调用。this_thread是个命名空间用于访问当前进程的属性。

默认构造函数

比如要创建一个线程池,但不清楚要创建多少个线程,就可以用thread()函数。

int n = 10;//线程个数
int m = 10;//每个线程跑m次
vector<thread> v_t;//创建n个线程对象,但每个线程都是空的
v.resize(n);//会调用线程的默认构造函数
for (auto& t : v_t)
{t = thread([m]{for (size_t i = 0; i < m; ++i){cout << std::this_thread::get_id() << " 跑" << endl;}});
}for (auto& t : v_t)
{t.join();
}

初始化线程

线程函数一般情况下可按照以下三种方式提供:函数指针;lambda表达式;函数对象。

线程函数的参数是以值拷贝的方式拷贝到线程独立栈空间中的,因此:即使线程参数为引用类型,在线程中修改后也不能修改外部实参,因为其实际引用的是线程栈中的拷贝,而不是外部实参。

拷贝构造函数=delete

thread类是防拷贝的,不允许拷贝构造以及赋值,但是可以移动构造和移动赋值,就是将一个线程对象关联线程的状态转移给其他线程对象,转移期间不影响线程的执行。

可以通过joinable()函数判断线程是否是有效的,如果是以下任意情况,则线程无效:采用无参构造函数构造的线程对象;线程对象的状态已经转移给其他线程对象;线程已经调用join或者detach结束。

注意,2个线程同时对一个变量int n = 0;进行++操作时,假设每个线程循环100次,只有可能小于期望数(200),不可能大于期望数(200)。且当循环次数越大时,错误越明显。

int val = 0;
mutex mtx;
void fun(int num)
{for (int i = 0; i < num; ++i){++val;}
}
int main()
{//两个线程可以调用同一个函数的原因:因为该函数是共享的,fun函数编译好以后是放在在主线程的代码段里,两个从线程都可以调用thread t1(fun, 100);thread t2(fun, 100);t1.join();t2.join();cout << val;//结果val<=200return 0;
}

注意fun里的加锁位置,放在for循环外面就是串行执行了,不过一个线程一旦申请成功,知道循环结束后才会释放锁,一个线程只需要一次加锁和解锁;放在for循环里面会导致频繁地切换上下文,加锁和解锁的次数跟循环次数相同了,增加了系统消耗。

使fun()函数线程安全的3种方法
//---------放在for循环外----------//运行速度快
void fun(int num)
{mtx.lock();for (int i = 0; i < num; ++i){++val;}mtx.unlock();
}
//---------放在for循环里----------//运行速度更慢
void fun(int num)
{	for (int i = 0; i < num; ++i){mtx.lock();++val;mtx.unlock();}	
}
//---------让++变成原子操作----------//
#include <atomic>
atomic_int val{ 0 };
void fun(int num)
{for (int i = 0; i < num; ++i){++val;}
}

原子性操作库

底层是靠CAS(compare and swap)来解决,windows和linux底层都有CAS。CAS操作包含3个操作数:1、内存位置V;2、预期原值A;3、新值B。若内存位置的值与预期原值匹配,那么处理器会自动将该位置更新为新值;否则,处理器不做任何处理。现在几乎所有的CPU指令都支持CAS的原子操作。

在C++11中,若提前声明该变量为原子性的,那么程序员不需要对原子类型变量进行加锁解锁操作,线程就能够对原子类型变量互斥访问。更方便的是,程序员可以使用atomic类模板,定义出需要的任意原子类型。

atomic<T> t;   // 声明一个类型为T的原子类型变量t
//atomic_int val{ 0 };
//atomic<int> val = 0;

注意:原子类型通常属于"资源型"数据,多个线程只能访问单个原子类型的拷贝,因此在C++11中,原子类型只能从其模板参数中进行构造,不允许原子类型进行拷贝构造、移动构造以及operator=等,为了防止意外,标准库已经将atmoic模板类中的拷贝构造、移动构造、赋值运算符重载默认删除掉了。

mutex互斥锁

std::recursive_mutex:递归里不可以用普通互斥锁。有专门的递归互斥锁,recursive_mutex(实现原理是根据线程id判断该线程是否已经加锁,已加锁则不执行,未加锁就加锁)。

std::timed_mutex:比 std::mutex 多了两个成员函数,try_lock_for()【接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住,在时间范围内还是没有获得锁,返回 false;否则该线程可以获得对互斥量的锁】,try_lock_until() 【接受一个时间点作为参数,在指定时间内还是没有获得锁,返回 false;否则该线程可以获得对互斥量的锁】。

lock_gurad

RAII。以独占所有权的方式管理mutex对象的上锁和解锁操作,即其对象之间不能发生拷贝。

实例化一个lock_guard对象,调用构造函数则表示成功上锁;出作用域前,lock_guard对象要被销毁,调用析构函数自动解锁。

lock_guard的缺陷:太单一,用户没有办法对该锁进行控制,因此C++11又提供了unique_lock。

C++11 unique_lock

RAII。以独占所有权的方式管理mutex对象的上锁和解锁操作,即其对象之间不能发生拷贝。unique_lock更加的灵活。

  • 上锁/解锁操作:lock、try_lock、try_lock_for、try_lock_until和unlock;
  • 修改操作:移动赋值、交换(swap:与另一个unique_lock对象互换所管理的互斥量所有权)、释放(release:返回它所管理的互斥量对象的指针,并释放所有权);
  • 获取属性:owns_lock(返回当前对象是否上了锁)、operator bool()(与owns_lock()的功能相同)、mutex(返回当前unique_lock所管理的互斥量的指针)

condition_variable

wait需要搭配unique_lock使用,pred一般传gelambda表达式

void wait (unique_lock<mutex>& lck);
//------------
template <class Predicate>
void wait (unique_lock<mutex>& lck, Predicate pred);==>相当于 while (!pred()) wait(lck);

notify_one在linux里就是signal,notify_all对于broadcast。

面试题:两个线程轮流打印奇数和偶数

面试题:并发与并行的区别

并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

并发和并行的区别:并发,指的是多个事情,在同一时间段内同时发生了。并行,指的是多个事情,在同一时间点上同时发生了。并发的多个任务之间是互相抢占资源的。并行的多个任务之间是不互相抢占资源的、只有在多CPU的情况中,才会发生并行。
在这里插入图片描述

相关文章:

C++11线程库

C11线程库 本质是对不同平台的线程库进行封装。因为windows和linux下各有自己的接口&#xff0c;这使得代码的可移植性比较差。C11中最重要的特性就是对线程进行支持了&#xff0c;使得C在并行编程时不需要依赖第三方库&#xff0c;而且在原子操作中还引入了原子类的概念。要使…...

智能化生产,提高效率!使用关键词采集工具助力企业数字化转型

关键词采集工具在企业数字化转型中的优势和作用进行阐述。 随着信息技术的不断发展&#xff0c;企业数字化转型已经成为了企业发展的必然趋势。 对于各种规模的企业而言&#xff0c;数字化转型可以提升企业的生产效率、降低成本、提高产品质量等方面带来更多的发展机遇。 而关…...

浅谈自动化测试用例创建和文档

通过自动创建测试用例和文档&#xff0c;探索自然语言处理 (NLP) 在革新软件测试方面的变革力量。 技术的快速发展导致对高效和有效的软件测试方法的需求增加。该领域最有前途的进步之一是自然语言处理 (NLP) 技术的集成。NLP 是人工智能(AI)的一个子集&#xff0c;专注于通过…...

[Java Web]AJAX Axios | 一种结合HTML来取代传统JSP的技术

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Java Web 目录1、AJAX1.1、简介1.2、作用1.3、同步和异步1.4、代码实现1.4.1、服务端1.4.2、客户端1.4.2.1、完善…...

【C++】多态问答题

前言 本篇仅整理一些比较偏的多态的问答题 文章目录前言一. 内联与虚函数二. 静态函数与虚函数三. 构造函数与虚函数四. 虚函数与普通函数结束语一. 内联与虚函数 内联函数可以是虚函数吗&#xff1f; 首先我们看一下语法有没有问题 我们看到&#xff0c;程序成功运行了&#…...

【设计模式】适配器模式

一&#xff0c;定义适配器模式&#xff1a;结构型模式之一&#xff0c;适配器提供客户类需要的接口&#xff0c;适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时&#xff0c;在适配器类的内部将调用适配者类的方法&#x…...

跨域之CorsFilter

跨域之CorsFilter CorsFilter 是 Spring 框架提供的一个用于处理跨域请求的过滤器。在开发中&#xff0c;我们常常需要处理前端发来的跨域请求&#xff0c;CorsFilter 就可以帮助我们实现这一功能。 CorsFilter 主要用于设置跨域请求的响应头&#xff0c;以允许跨域请求能够被…...

STM32基于HAL工程读取DS1302时间数据

STM32基于HAL工程读取DS1302时间数据✨申明&#xff1a;本文章仅发表在CSDN网站&#xff0c;任何其他网站&#xff0c;未注明来源&#xff0c;见此内容均为盗链和爬取&#xff0c;请多多尊重和支持原创!&#x1f341;对于文中所提供的相关资源链接将作不定期更换。&#x1f4cc…...

《Effective Objective-C 2.0 》 阅读笔记 item10

第10条&#xff1a;在既有类中使用关联对象存放自定义数据 1. 关联对象 可以给某对象关联许多其他对象&#xff0c;这些对象通过“键”来区分&#xff0c;这就是关联对象。存储对象值的时候&#xff0c;可以指明“存储策略”&#xff08;storage policy&#xff09;&#xff…...

gpt3官网中文版-人工智能软件chat gpt安装

GPT-3&#xff08;Generative Pre-trained Transformer 3&#xff09;是一种自然语言处理模型&#xff0c;由OpenAI研发而成。它是GPT系列模型的第三代&#xff0c;也是目前最大、最强大的自然语言处理模型之一&#xff0c;集成了1750亿个参数&#xff0c;具有广泛的使用场景&a…...

工作常用、面试必问:Hive 窗口函数汇总

在SQL中有一类函数叫做聚合函数&#xff0c;例如sum()、avg()、max()等等&#xff0c;这类函数可以将多行数据按照规则聚集为一行&#xff0c;一般来讲聚集后的行数是要少于聚集前的行数的。但是有时我们想要既显示聚集前的数据&#xff0c;又要显示聚集后的数据&#xff0c;这…...

spring5(五):AOP操作

spring5&#xff08;五&#xff09;&#xff1a;AOP操作前言一、代理模式1、场景模拟2、代理模式2.1 概念2.2 静态代理2.3 动态代理二、AOP概述1、什么是 AOP?2、相关术语3、作用三、AOP底层原理1、AOP 底层使用动态代理2、AOP&#xff08;JDK 动态代理&#xff09;2.1 编写 J…...

functional.partial

functional.partial__slots____new__中的cls, /是什么意思&#xff1f;functools.partial这个partial类有什么作用类中没有__init__函数Python 内置的 functools.partial 类的实现。这个类可以用来创建一个新的函数对象&#xff0c;该对象是对一个原有函数的参数进行了部分应用…...

C#缩放PDF文件

项目上有个功能需求&#xff1a;将原PDF进行缩放至原先的90%大小。 使用的是spire.pdf插件&#xff0c;但是官方文档上的缩放只是改变显示&#xff0c;最终文件其实没有缩放成功。遂找到了另外的方式进行重绘。 上代码&#xff1a; using Spire.Pdf; using Spire.Pdf.Graphi…...

【Java面试八股文宝典之MySQL篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day20

大家好&#xff0c;我是陶然同学&#xff0c;软件工程大三即将实习。认识我的朋友们知道&#xff0c;我是科班出身&#xff0c;学的还行&#xff0c;但是对面试掌握不够&#xff0c;所以我将用这100多天更新Java面试题&#x1f643;&#x1f643;。 不敢苟同&#xff0c;相信大…...

Nsight System的安装和使用

本地安装 官方网站&#xff0c;需要登录 选择Windows Host下载安装 服务器安装 选择Linux CLI .deb下载&#xff0c;上传到服务器之后&#xff0c;执行以下命令&#xff0c;默认会安装在/opt/nvidia/nsight-systems-cli/2023.2.1/target-linux-x64/&#xff0c;nsys在/usr/lo…...

Spring销毁的几种实现

有这3种方法&#xff0c;但是程序执行完成并没有打印出来。一定要手动close.手动执行后会调用如下逻辑&#xff1a;org.springframework.context.support.AbstractApplicationContext#doCloseorg.springframework.context.support.AbstractApplicationContext#destroyBeansorg.…...

【 Spring 核⼼与设计思想 】

文章目录一、Spring 是什么1.1 什么是容器1.2 什么是 IoC二、开发案例对比2.1 传统程序开发2.2 控制反转式程序开发2.3 对⽐总结规律三、理解 Spring IoC四、DI 概念说明五、总结一、Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&…...

Arrays.sort()——逆序

package utils;import java.util.*;class ComparatorInteger implements Comparator<Integer> {Override //使得逆序 o1比o2小&#xff0c;返回正数——需要调换位置public int compare(Integer o1, Integer o2) {return o1 < o2 ? 1 : -1;} }class Comparato…...

测试2年遇到瓶颈,如何跨过这个坎,实现涨薪5k?

最近和字节跳动的一个老朋友闲聊&#xff0c;感触颇深&#xff0c;据他说公司近期招聘的测试工程师&#xff0c;大多数候选人都有一个“通病”&#xff1a;在工作2-3年的时候遇到瓶颈&#xff0c;而且是一道很难跨越的坎。为什么会遇到这种情况&#xff1f;因为大部分测试工程师…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

智能AI电话机器人系统的识别能力现状与发展水平

一、引言 随着人工智能技术的飞速发展&#xff0c;AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术&#xff0c;在客户服务、营销推广、信息查询等领域发挥着越来越重要…...