【C/C++ 16】C++11线程库

目录

一、thread类概述

二、多线程

三、原子性操作库

四、lock_guard

五、unique_guard


一、thread类概述

进程是操作系统进行资源调度的最小单位,线程是CPU进行任务执行的最小单位。

在C++11之前,涉及到多线程问题,都是和平台相关的,比如windows和linux下各有自己的接口,这使得代码的可移植性比较差。C++11中最重要的特性就是对线程进行支持了,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。

要使用标准库中的线程,必须包含 <thread> 头文件,在Linux系统编译时加上 -lpthread

函数名功能
thread()构造一个线程对象,不关联任何线程函数
thread(fn, args1, args2...)

构造一个线程对象,并关联线程函数fn,

args1、args2...为线程函数的参数

get_id()获取线程id
jionable()线程是否在执行,joinable()代表一个正在执行中的线程
join()阻塞等待子线程结束
detach()分离子线程为后台线程,即子线程的运行状态不再影响主线程

当创建一个线程对象后,并且给线程关联线程函数,该线程就被启动,与主线程一起运行。

二、多线程

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <thread>
using namespace std;void ThreadFunc(int a)
{cout << "Thread1: " << a << endl;
}class TF
{
public:void operator()(int a){cout << "Thread2: " << a << endl; }
};int main()
{std::thread t1(ThreadFunc, 10);std::thread t2(TF(), 20);std::thread t3([](int a) {cout << "Thread3: " << a << endl; }, 30);t1.join();t2.join();t3.join();cout << "Main Thread!" << endl;return 0;
}// 由运行结果可见,父线程与子线程之间的运行顺序是随机的// 并发:一个CPU同时处理多个线程任务(宏观上同时执行,微观上交替执行)
// 并行:多个CPU同时处理多个线程任务(也可以理解为一个CPU的多个核心同时处理多个任务)

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

可以通过jionable()函数判断线程是否是有效的,如果是以下任意情况,则线程无效:

  1. 采用无参构造函数构造的线程对象
  2. 线程对象的状态已经转移给其他线程对象
  3. 线程已经调用jion或者detach结束

三、原子性操作库

多线程共享同一个进程的资源,由于多个线程的执行顺序是随机的,所以在访问统一进程空间中的共享内存(临界资源)时,会发生线程安全问题。

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <thread>
using namespace std;unsigned long g_sum = 0L;void fun(size_t num)
{for (size_t i = 0; i < num; ++i)g_sum++;
}int main()
{cout << "Before joining,sum = " << g_sum << std::endl;thread t1(fun, 10000000);thread t2(fun, 10000000);t1.join();t2.join();cout << "After joining,sum = " << g_sum << std::endl;return 0;
}

C++传统的方式是通过加锁来控制多线程对临界资源的访问,但是加锁有一个缺陷,就是一个线程对数据进行加锁操作之后,其他线程要是也想访问这个数据,就只能阻塞等待,这大大降低了多线程的效率,并且加锁还有一个缺陷就是容易引起死锁问题,不过死锁问题可以通过智能指针解决。

C++11引入了原子操作库 <atomic>,并提供了原子操作类型,是线程同步变得高效。

原子类型名称对应的内置类型名称
atomic_boolbool
atomic_charchar
atomic_intint
atomic_uintunsigned int
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <thread>
#include <atomic>
using namespace std;atomic_int g_sum = 0;void fun(size_t num)
{for (size_t i = 0; i < num; ++i)g_sum++;
}int main()
{cout << "Before joining,sum = " << g_sum << std::endl;thread t1(fun, 10000000);thread t2(fun, 10000000);t1.join();t2.join();cout << "After joining,sum = " << g_sum << std::endl;return 0;
}

在C++11中,程序员不需要对原子类型变量进行加锁解锁操作,线程能够对原子类型变量互斥的访问。更为普遍的,程序员可以使用atomic类模板,定义出需要的任意原子类型。

atmoic<T> t; // 声明一个类型为T的原子类型变量t

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

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <thread>
#include <atomic>
using namespace std;#include <atomic>
int main()
{atomic<int> a1(0);//atomic<int> a2(a1); // 编译失败atomic<int> a2(1);//a2 = a1; // 编译失败cout << a1 << ' ' << a2 << endl;return 0;
}

四、lock_guard

在多线程环境下,如果想要保证某个变量的安全性,只要将其设置成对应的原子类型即可,即高效又不容易出现死锁问题。但是有些情况下,我们可能需要保证一段代码的安全性,那么就只能通过锁的方式来进行控制。

在C++11中,Mutex总共包了四个互斥量的种类:

  1. std::mutex,互斥锁,最常用
  2. std::recursive_mutex,允许同一个线程对互斥量多次上锁(即递归上锁)
  3. std::timed_mutex,比 std::mutex 多了两个成员函数,try_lock_for(),try_lock_until()
  4. std::recursive_timed_mutex

为了防止死锁问题,C++11采用RAII的方式对锁进行了封装,即 lock_guard unique_lock 。 

std::lock_gurad 是 C++11 中定义的模板类。

namespace my
{template<class _Mutex>class lock_guard{public:// 关键字explicit可以阻止隐式转换的发生explicit lock_guard(_Mutex& mtx): _mtx(mtx){_mtx.lock();}~lock_guard(){_mtx.unlock();}lock_guard(const lock_guard<_Mutex>&) = delete;lock_guard<_Mutex>& operator=(const lock_guard<_Mutex>&) = delete;private:_Mutex& _mtx;};
}

lock_guard类模板主要是通过RAII的方式,对其管理的互斥量进行了封装,在需要加锁的地方,只需要用上述介绍的任意互斥体实例化一个lock_guard,调用构造函数成功上锁,出作用域前,lock_guard对象要被销毁,调用析构函数自动解锁,可以有效避免死锁问题。

五、unique_guard

与lock_gard类似,unique_lock类模板也是采用RAII的方式对锁进行了封装,并且也是以独占所有权的方式管理mutex对象的上锁和解锁操作,即其对象之间不能发生拷贝。

在构造(或移动(move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。

使用以上类型互斥量实例化 unique_lock的对象时,自动调用构造函数上锁,unique_lock对象销毁时自动调用析构函数解锁,可以很方便的防止死锁问题。

与lock_guard不同的是,unique_lock更加的灵活,提供了更多的成员函数:

  1. 上锁/解锁操作:lock、try_lock、try_lock_for、try_lock_until和unlock
  2. 修改操作:移动赋值、交换(swap:与另一个unique_lock对象互换所管理的互斥量所有权)、释放(release:返回它所管理的互斥量对象的指针,并释放所有权)
  3. 获取属性:owns_lock(返回当前对象是否上了锁)、operator bool()(与owns_lock()的功能相同)、mutex(返回当前unique_lock所管理的互斥量的指针)
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;void PrintTwoThread()
{mutex mtx;condition_variable c;int n = 100;bool flag = true;thread t1([&] {int i = 0;while (i < n){unique_lock<mutex> lock(mtx);c.wait(lock, [&]()->bool {return flag; });cout << i << endl;i += 2;flag = false;c.notify_one();}});thread t2([&] {int j = 1;while (j < n){unique_lock<mutex> lock(mtx);c.wait(lock, [&]()->bool {return !flag; });cout << j << endl;j += 2;flag = true;c.notify_one();}});t1.join();t2.join();
}int main()
{PrintTwoThread();return 0;
}

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

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

相关文章

Solidworks:平面工程图练习

把草图变成工程图&#xff0c;遇到第一个问题是线宽需要用鼠标选中后再设置线宽和颜色。我觉得应该有一个自动设置现款的功能&#xff0c;不知道有没有&#xff0c;我找了半天也没找到。 另一个问题是&#xff0c;作业代号字体上下颠倒了&#xff0c;不知道这是啥意思。 第三个…

[缓存] - Redis

0.为什么要使用缓存&#xff1f; 用缓存&#xff0c;主要有两个用途&#xff1a;高性能、高并发。 1. 高性能 尽量使用短key 不要存过大的数据 避免使用keys *&#xff1a;使用SCAN,来代替 在存到Redis之前压缩数据 设置 key 有效期 选择回收策略(maxmemory-policy) 减…

springboot177健身房管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

XGboost集成学习

XGBoost集成学习是一种基于决策树的集成方法&#xff0c;用于解决分类和回归问题。它是一种Gradient Boosting&#xff08;梯度提升&#xff09;的改进版&#xff0c;通过使用一系列弱学习器&#xff08;例如决策树&#xff09;的集合来构建一个更强大的模型。 XGBoost通过迭代…

DevOps:CI、CD、CB、CT、CD

目录 一、软件开发流程演化快速回顾 &#xff08;一&#xff09;瀑布模型 &#xff08;二&#xff09;原型模型 &#xff08;三&#xff09;螺旋模型 &#xff08;四&#xff09;增量模型 &#xff08;五&#xff09;敏捷开发 &#xff08;六&#xff09;DevOps 二、走…

python的os库常用代码

了解路径&#xff0c;就一定要先了解正斜杠 / 和反斜杠 \。在 MacOS 和 Linux 系统下&#xff0c;路径默认使用的都是正斜杠/&#xff0c;在Windows系统下&#xff0c;正反斜杠都可以表示路径分隔符&#xff0c;默认的是反斜杠 \。由于反斜杠本身属于转义符&#xff0c;如 \n 表…

Rust复合类型详解

在Rust中&#xff0c;复合类型是一种能够将多个值组合在一起的数据类型。本篇博客将介绍两种常见的复合类型&#xff1a;元组&#xff08;Tuple&#xff09;和数组&#xff08;Array&#xff09;。 Tuple&#xff08;元组&#xff09; 元组是Rust中的一种复合类型&#xff0c…

机器学习:过拟合和欠拟合的介绍与解决方法

过拟合和欠拟合的表现和解决方法。 其实除了欠拟合和过拟合&#xff0c;还有一种是适度拟合&#xff0c;适度拟合就是我们模型训练想要达到的状态&#xff0c;不过适度拟合这个词平时真的好少见。 过拟合 过拟合的表现 模型在训练集上的表现非常好&#xff0c;但是在测试集…

代码随想录刷题笔记 DAY 23 | 修剪二叉搜索树 No.669 | 将有序数组转换为二叉搜索树 No.108 | 把二叉搜索树转换为累加树 No.538

文章目录 Day 2301. 修剪二叉搜索树&#xff08;No. 669&#xff09;1.1 题目1.2 笔记1.3 代码 02. 将有序数组转换为二叉搜索树&#xff08;No. 108&#xff09;2.1 题目2.2 笔记2.3 代码 03. 把二叉搜索树转换为累加树&#xff08;No. 538&#xff09;3.1 题目3.2 笔记3.3 代…

Vue - 快速入门(一)

阅读文章可以收获&#xff1a; 1. 明白什么是vue 2. 如何创建一个vue实例 3. vue中的插值表达式如何使用 4. 如何安装vue的开发者工具 Vue 概念 什么是vue&#xff1f; Vue 是一个用于 构建用户界面 的 渐进式 框架 框架优点&#xff1a;大大提升开发效率 (70%↑) 缺点…

第80讲订单管理功能实现

后端 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace"com.java1234.mapper.OrderM…

深入学习Pandas:数据连接、合并、加入、添加、重构函数的全面指南【第72篇—python:数据连接】

深入学习Pandas&#xff1a;数据连接、合并、加入、添加、重构函数的全面指南 Pandas是Python中最强大且广泛使用的数据处理库之一&#xff0c;提供了丰富的函数和工具&#xff0c;以便更轻松地处理和分析数据。在本文中&#xff0c;我们将深入探讨Pandas中一系列数据连接、合…

python中的数组和list的异同

在Python中&#xff0c;数组和列表&#xff08;list&#xff09;是两个非常相似但又不完全一样的数据结构。实际上&#xff0c;Python本身并没有原生的数组类型&#xff0c;而列表&#xff08;list&#xff09;是Python提供的一种非常灵活且常用的序列类型。下面我将简要介绍它…

【教程】autojs使用Intent打开相机拍照并指定存储路径

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] var photoPath "/sdcard/a.jpg"; var photoFile new java.io.File(photoPath); if (!photoFile.exists()) {photoFile.getParentFile().mkdirs();} try {photoFile.createNewFile(); } catch (e) {to…

React18原理: 再聊Fiber架构下的时间分片

时间分片 react的任务可以被打断&#xff0c;其实就是基于时间分片的人眼最高能识别的帧数不超过30帧&#xff0c;电影的帧数差不多是在24浏览器的帧率一般来说是60帧&#xff0c;也就是每秒60个画面, 平均一个画面大概是16.5毫秒左右浏览器正常的工作流程是运算渲染&#xff…

【iOS操作系统——讲解】

iOS操作系统 iOS操作系统 iOS操作系统 iOS是苹果公司开发的移动操作系统&#xff0c;最初在2007年推出&#xff0c;当时伴随着第一代iPhone一起亮相&#xff0c;iOS是基于Darwin (BSD)操作系统核心的&#xff0c;并且具有对多点触控手势的原生支持&#xff0c;这些手势在iOS界…

UVA11181条件概率 Probability|Given

条件概率 Probability|Given - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 样例解释&#xff1a; 需要学习条件概率和贝叶斯定理 //1 2 - 0.1*0.2*(1-0.3) 0.014 //1 - 3 0.1*0.8*0.3 0.024 //- 2 3 0.9*0.2*0.3 0.054 // 0.092//(0.0140.024)/0.092 0.4…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之QRCode组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之QRCode组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、QRCode组件 用于显示单个二维码的组件。 子组件 无。 接口 QRCode(value: st…

python-分享篇-GUI界面开发-PyQt5-对QListWidget列表进行数据绑定

代码 # -*- coding: utf-8 -*-# Form implementation generated from reading ui file bindlist.ui # # Created by: PyQt5 UI code generator 5.11.3 # # WARNING! All changes made in this file will be lost! 对QListWidget列表进行数据绑定from PyQt5 import QtCore, QtG…

Elasticsearch:混合搜索是 GenAI 应用的未来

在这个竞争激烈的人工智能时代&#xff0c;自动化和数据为王。 从庞大的存储库中有效地自动化搜索和检索信息的过程的能力变得至关重要。 随着技术的进步&#xff0c;信息检索方法也在不断进步&#xff0c;从而导致了各种搜索机制的发展。 随着生成式人工智能模型成为吸引力的中…