【C++】多线程的学习笔记(2)——白话文版(bushi

目录

前一篇

本章内容提要

使用mutex锁的原因

mutex锁的概念

mutex的使用教程

锁的声明以及命名

mutex的加锁以及解锁

例子

结果

注意

mutex的其他方式的锁介绍

lock_guard

介绍

例子

运行结果

adopt_lock参数

unique_lock

介绍

try_to_lock

defer_lock

release

例子

结果

总结


前一篇

第一篇在这

【C++】多线程的学习笔记——白话文版(bushi-CSDN博客C++ 作为一种强大的编程语言,为多线程编程提供了丰富而灵活的支持。C++ 的标准库提供了头文件,其中包含了用于创建、启动和管理线程的类和函数。通过使用这些多线程库和功能,开发人员可以轻松地引入并发性到自己的应用程序中,实现多线程的并行处理。thread函数中定义线程的语法规如下std::thread 变量名 (函数,传递的参数1,传递的参数2,传递的参数3...)【如果前面加了using namespace std;可以删除std::】https://blog.csdn.net/mumuemhaha/article/details/133468825?spm=1001.2014.3001.5502

本章内容提要

上一章我们讲解了如何利用thread库初步进行多线程操作

这一章,我们主要讲的是锁(其实就是mutex锁)的概念

使用mutex锁的原因

在上一章的多线程操作中我们也许会想到一个问题——如果变量或者资源他不是独占的,而是共享的(比如对于全局变量的修改),那么如果多个线程同时访问就会引起不可预料的错误

这个时候就必须要给线程进行加锁确保只能有一个线程运行此函数。

mutex锁的概念

Mutex(互斥锁)是一种线程同步机制,用于保护共享资源的访问,防止多个线程同时访问和修改同一份数据而引发竞争条件(race condition)。

Mutex 的作用是在关键代码段前后加锁和解锁操作,确保只有一个线程能够进入临界区(critical section)执行代码,从而保证共享资源的安全访问。

同一时刻,同一临界区,只能有一个线程持有该锁

mutex的使用教程

锁的声明以及命名

开头必然要声明库函数

#include <mutex>

和其他类型的变量一样,之后锁还需要声明一个变量

mutex mtx_1;

这个最好是在全局变量中进行声明

mutex的加锁以及解锁

在你写函数需要加锁时你只需要调用他们当中的lock(),以及unlck(),如果在执行lock时候如果锁已经被其他线程获取了,那么线程会进行等待

拿上面的进行举例就是

mtx_1.lock();//加锁
mtx_1.unlock();//解锁

例子

运行一个

#include <iostream>
#include <thread>
#include <time.h>
#include <vector>
#include <mutex>
using namespace std;
mutex mtx_1;
void F_1(int i) {mtx_1.lock();cout << "This is NO." << i << " project is runing." << endl;this_thread::sleep_for(chrono::seconds(i));cout << "This is NO." << i << " project is finishing." << endl;mtx_1.unlock();
}
int main() {clock_t now_time_1 = clock();cout << "This project is start!" << endl;//记录刚刚开始的时间vector<thread>sum_1;for (int i = 1; i <= 3; i++) {sum_1.push_back(thread(F_1, i));}for (int i = 0; i <= sum_1.size() - 1; i++) {sum_1[i].join();}cout << "This project is ready!" << endl;//记录结束的时间clock_t now_time_2 = clock();cout << "The cost time is " << now_time_2 - now_time_1 << " ms " << endl;return 0;
}

简单的代码

结果

可能有人就要问,这不和之前顺序执行的时间一样吗?

先不要急,这只是举一个例子,例子也比较极端开头就锁上了,事实上你只需要在有资源冲突的函数部分加锁即可,其他的地方依旧可以和以前一样,甚至不同的函数你可以命名两个锁分别进行执行加锁或者是解锁。

换言之,锁只是在你需要确保该资源变量在同一时刻只被一个线程访问时加上即可。

注意

需要注意的是需要避免的是:两个或者多个线程之间所需要的资源被另外的线程锁住,从而造成死锁。

mutex的其他方式的锁介绍

lock_guard

介绍

lock_guard是模板类,对比于mutex的区别是lock_guard在创建时会尝试获得锁的所有权(注意时尝试,如果获取不到就相当于没有用,并且不会报错),在作用域结束时会自动析构,无需手动解锁

该类不可中途上锁和解锁,不可复制

例子

还是之前的代码

#include <iostream>
#include <thread>
#include <time.h>
#include <vector>
#include <mutex>
using namespace std;
mutex mtx_1;
void F_1(int i) {lock_guard<mutex>guard_1(mtx_1);cout << "This is NO." << i << " project is runing." << endl;this_thread::sleep_for(chrono::seconds(i));cout << "This is NO." << i << " project is finishing." << endl;
}
int main() {clock_t now_time_1 = clock();cout << "This project is start!" << endl;//记录刚刚开始的时间vector<thread>sum_1;for (int i = 1; i <= 3; i++) {sum_1.push_back(thread(F_1, i));}for (int i = 0; i <= sum_1.size() - 1; i++) {sum_1[i].join();}cout << "This project is ready!" << endl;//记录结束的时间clock_t now_time_2 = clock();cout << "The cost time is " << now_time_2 - now_time_1 << " ms " << endl;return 0;
}

运行结果

他并不需要解锁和解锁 

adopt_lock参数

adopt_lock用法为

lock_guard<mutex>guard_1(mtx_1,adopt_lock);

 加了这个参数,就可以在创建时候不上锁,代表表示这个互斥量已经lock();优化代码的运行时间,同时这个参数本质时起到一个标记

但是需要注意由于lock_guard不可以主动上锁,如果这个锁本身还没有lock过就会报错。

unique_lock

介绍

unique_lock的用法和lock_guard的用法类似,主要的区别在于他可以中途上锁以及解锁

对比于lock_guard会更加的灵活

但是所需要的内存空间会更大

同时它的也有adopt_lock参数用法一样,而且他还拥有其他的第二参数

try_to_lock

他会尝试的去获取锁,如果锁没有被占用就会获取到,如果已经被占用了也会立即放回执行下面的代码不会进行堵塞,用法和adopt_lock一样

defer_lock

创建锁的时候不上锁(需要注意区分前面的adopt_lock()这个时没上锁的前提下(如果上锁了会报错)创建该锁时不上锁。之后再进行上锁。),用法也和adopt_lock一样

release

为释放unique_lock的所有权,注意是释放——release!!!!不是解锁——unlock,之后的锁需要你自己来管理

例子

还是之前的代码中的函数

void F_1(int i) {unique_lock<mutex>guard_1(mtx_1);mutex* mtx_2 = guard_1.release();cout << "This is NO." << i << " project is runing." << endl;this_thread::sleep_for(chrono::seconds(i));cout << "This is NO." << i << " project is finishing." << endl;mtx_2->unlock();
}
结果

 当然还是一样的

总结

本章讲解了mutex大部分的知识点,使用时需要注意锁住的代码要尽可能的少而精准,这样程序的运行时间和稳定性以及安全性才可以同时得到显著的提升。

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

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

相关文章

堆排序——向下调整

之前我们要想实现堆排序&#xff0c;是运用建堆代码来实现的&#xff1a; 向上调整建堆——向下调整排序 那么去我们可不可以只适用一种调整方法&#xff08;向下调整&#xff09;就能实现这样的功能呢&#xff1f; 向要只使用向下调整就实现堆排序 首先就是把数组里的值使用…

Linux--socket编程

socket套接字编程 一、服务器和客户端的开发步骤&#xff1a; 1、创建套接字 2、为套接字添加信息&#xff08;ip地址和端口号&#xff09; 3、监听网络连接 4、监听到有客户端接入&#xff0c;接受连接&#xff08;如没有接入&#xff0c;会发生阻塞到&#xff09; 5、数据…

导出视频里的字幕

导出视频里的字幕 如何利用剪映快速提取并导出视频里的字幕 https://jingyan.baidu.com/article/c35dbcb0881b6fc817fcbcd2.html 如何快速提取视频中的字幕&#xff1f;给大家介绍一种简单高效又免费的提取方法。需要利用到“剪映”&#xff0c;以下是具体的操作步骤和指引&a…

第2篇 机器学习基础 —(1)机器学习方式及分类、回归

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。机器学习是一种人工智能的分支&#xff0c;它使用算法和数学模型来使计算机系统能够从经验数据中学习和改进&#xff0c;而无需显式地编程。机器学习的目标是通过从数据中发现模式和规律&#xff0c;从而使计算机能够自动进…

SpringMVC(二)@RequestMapping注解

我们先新建一个Module。 我们的依赖如下所示&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaL…

Is This The Intelligent Model(这是智能模型吗)

Is This The Intelligent Model 这是智能模型吗 Ruoqi Sun Academy of Military Science Defense Innovation Institute, Beijing, 100091, China E-mail: ruoqisun7163.com The exposed models are called artificial intelligent models[1-3]. These models rely on knowled…

LOD1.3快速构建 | 多源数据自动化作业、图元和体块模型快速编辑、智能纹理贴图...

2023年&#xff0c;自然资源部先后发布了《实景三维中国建设总体实施方案&#xff08;2023—2025年&#xff09;》、《实景三维中国建设城市三维模型快速构建技术规定&#xff08;征求意见稿&#xff09;》等文件&#xff0c;明确提出&#xff0c;2024年底完成城市三维模型&…

[Unity][VR]Oculus透视开发图文教程1-Passthrough应用XR项目设置

Oculus现在已向开发者公布了如何使用自己的设备Camera,本系列课程就来手把手地告诉你如何在Unity中使用这个特性。 第一步,既然用的是Quest的特性,那就需要先引入Quest的Unity开发SDK。并且完成基本的VR开发项目设置。 新建Unity项目后,在编辑器界面先点击Window,打开资…

Go基础之变量和常量

Go基础之变量和常量 文章目录 Go基础之变量和常量一. 标识符、关键字、内置类型和函数1.1 标识符1.2 关键字1.3 保留字1.4 内置类型1.4.1 值类型&#xff1a;1.4.2 引用类型&#xff1a;(指针类型)1.5 内置函数1.6 内置接口error 二.Go变量命名规范2.1 采用驼峰体命名2.2 简单、…

Redis作为缓存,mysql的数据如何与redis进行同步?

Redis作为缓存&#xff0c;mysql的数据如何与redis进行同步&#xff1f; 一定要设置前提&#xff0c;先介绍业务背景 延时双删 双写一致性:当修改了数据库的数据也要同时更新缓存的数据&#xff0c;缓存和数据库的数据要保持一致 读操作:缓存命中&#xff0c;直接返回;缓存未…

pandas read_json时ValueError: Expected object or value的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

K8S网络原理

文章目录 一、Kubernetes网络模型设计原则IP-per-Pod模型 二、Kubernetes的网络实现容器到容器的通信Pod之间的通信同一个Node内Pod之间的通信不同Node上Pod之间的通信 CNI网络模型CNM模型CNI模型在Kubernetes中使用网络插件 开源的网络组件FlannelFlannel实现图Flannel特点 Op…