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

C++学习0.2: RAII

引用: 

【代码质量】RAII在C++编程中的必要性_raii 在c++中的重要性-CSDN博客

C++ RAII典型应用之lock_guard和unique_lock模板_raii lock-CSDN博客

前言:

常用的线程间同步/通信(IPC)方式有锁(互斥锁、读写锁、自旋锁)、屏障、条件变量、信号量、消息队列。其中锁一种最常用的一种IPC,用于对多个线程共享的资源进行保护,达到线程互斥访问资源的目的。以互斥锁为例,其中最常见的异常而且是致命的问题是——“死锁”。
  死锁(DeadLock) 是指两个或者两个以上的进程(线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,导致两者的任务都无法继续执行下去,直至重新执行程序。

基于RAII(Resource Acquisition Is Initialization)设计理念,C++ 11引入了lock_guardunique_lock类模板,以尽可能避免死锁产生。

2 lock_guard

lock_guard是C++ 11引入的一个互斥锁类模板。lock_guard基于RAII设计理念,将互斥锁的作用范围和(对象)作用域绑定,函数退出作用域后,自动释放锁资源避免忘记解锁造成的死锁现象。

lock_guard具有如下特点:

  • 创建lock_guard对象,即获取互斥锁权限,并上锁
  • 作用域中途不能解锁
  • 退出lock_guard对象作用域后,自动解锁
  • lock_guard 锁不能复制且不能移动,禁止拷贝构造和移动构造

3 lock_guard使用

lock_guard使用比较简单:

  • 首先需要包含mutex头文件
  • 然后创建一个锁实例mutex
  • 在需要加锁的作用域内,创建以锁示例mutex作为形参的lock_guard对象

伪代码实现过程:

#include <mutex>    /* for std::mutex std::lock_guard */std::mutex mutex;void func(void)
{const std::lock_guard<std::mutex> lock(mutex);/* todo,上锁区域;无需手动解锁,*/
}

写个例子,代码实现功能:

  • 创建两个线程
  • 线程分别对全局变量访问,并输出到终端
  • 期望结果,线程1输出结果“ 1 2 3 4 5”,线程2输出结果“5 4 3 2 1”
#include <stdio.h>
#include <thread>
#include <mutex>
#include <iostream>
#include <unistd.h>
#include "pthread.h" #define	USE_MUTEX 1	/* 是否使用互斥锁,使用,0不使用 */#if USE_MUTEX
std::mutex s_mutex;
#endifstatic int8_t g_count = 0;void *thread0_entry(void *data)  
{uint8_t  i =0;#if USE_MUTEXconst std::lock_guard<std::mutex> lock(s_mutex);
#endiffor (i = 0;i < 5;i++){g_count ++;printf("%d ", g_count);usleep(100);}printf("\r\n");
}void *thread1_entry(void *data)  
{uint8_t  i =0;#if USE_MUTEXconst std::lock_guard<std::mutex> lock(s_mutex);
#endiffor (i = 0;i < 5;i++){printf("%d ", g_count);g_count--;usleep(100);}printf("\r\n");
}int main(int argc, char **argv)  
{pthread_t thread0;pthread_t thread1; void *retval; pthread_create(&thread0, NULL, thread0_entry, NULL);pthread_create(&thread1, NULL, thread1_entry, NULL);pthread_join(thread0, &retval);pthread_join(thread1, &retval);return 0;}

分别编译启用锁和不启用锁的版本,并打印出程序输出。

#不开启锁版本
chenhaoxu@chenhaoxu-VirtualBox:~/work/test/cpp$ ./test
thread 1: thread 2: 0 0 1 1 02 1 0  1 1#开启锁版本
chenhaoxu@chenhaoxu-VirtualBox:~/work/test/cpp$ ./test
thread 1: 0 1 2 3 4 
thread 2: 5 4 3 2 1 
chenhaoxu@chenhaoxu-VirtualBox:~/work/test/cpp$

4 unique_lock

unique_lock 是 lock_guard 的衍生版,除了具备lock_guard的完整功能,还增加了自身特有的功能,以适应一些lock_guard无法实现的复杂加锁场景。与lock_guard,相比,unique_lock增加的特性包括:

  • 任意时候上锁(指定第二个参数为std::defer_lock),非创建即上锁
void fun0(void) 
{std::unique_lock<std::mutex> ulock(mutex, std::defer_lock); /* 创建对象,不上锁 *//* todo */guard.lock(); /* 上锁 *//* 退出作用域,自动解锁 */
}
  • 提供解锁接口unlock,可以中途解锁,非等退出作用域后才解锁
void fun1(void) 
{std::unique_lock<std::mutex> ulock(mutex);/* todo */guard.unlock(); /* 解锁 *//* todo */guard.lock(); /* 继续上锁 *//* 退出作用域,自动解锁 */
}
  • 不可复制,但可移动
/* lock_guard 不可复制,不可移动 */
std::lock_guard<std::mutex> lock0(mutex);
std::lock_guard<std::mutex> lock1 = lock0;  /* error */
std::lock_guard<std::mutex> lock1 = std::move(lock0); /* error *//* unique_lock 不可复制,可以移动 */
std::unique_lock<std::mutex> ulock0(mutex);
std::unique_lock<std::mutex> ulock1 = ulock0;  /* error */
std::unique_lock<std::mutex> ulock1 = std::move(ulock0); /* ok */

使用原则:

  lock_guard使用简单,效率高;unique_lock使用比较灵活,效率比lock_guard稍微低一点,因为其内部需要维护锁的状态。关于选择使用原则:lock_guard能解决问题的时候,选择lock_guard;否则选择unique_lock。


  注意:lock_guard和unique_lock只支持STL的mutex,不支持POSIX标准的mutex(pthread_mutex_t)。至少目前未支持,编译会失败。

相关文章:

C++学习0.2: RAII

引用&#xff1a; 【代码质量】RAII在C编程中的必要性_raii 在c中的重要性-CSDN博客 C RAII典型应用之lock_guard和unique_lock模板_raii lock-CSDN博客 前言: 常用的线程间同步/通信&#xff08;IPC&#xff09;方式有锁&#xff08;互斥锁、读写锁、自旋锁&#xff09;、…...

k8s,进一步理解Pod

比如&#xff0c;凡是调度、网络、存储&#xff0c;以及安全相关的属性&#xff0c;基本上是Pod 级别的。 这些属性的共同特征是&#xff0c;它们描述的是“机器”这个整体&#xff0c;而不是里面运行的“程序”。比如&#xff0c;配置这个“机器”的网卡&#xff08;即&#…...

MFC图形函数学习13——在图形界面输出文字

本篇是图形函数学习的最后一篇&#xff0c;相关内容暂告一段落。 在图形界面输出文字&#xff0c;涉及文字字体、大小、颜色、背景、显示等问题&#xff0c;完成这些需要系列函数的支持。下面做简要介绍。 一、输出文本函数 原型&#xff1a;virtual BOOL te…...

【Canvas与雷达】点鼠标可暂停金边蓝屏雷达显示屏

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>点鼠标可暂停金边蓝屏雷达显示屏 Draft1</title><style typ…...

React第十二节组件之间通讯之发布订阅模式(使用pubsub-js插件)

组件之间通讯常用方案 1、通过props 2、通过context 3、通过发布订阅模式 4、通过Redux 后面会有专栏介绍 1、安装 pubsub-js 插件 yarn add pubsub-js 常用的事件 a、发布事件&#xff1a;传入一个自定义事件名称&#xff08;name&#xff09;&#xff0c;以及要发布的消息内…...

Vue3安装 运行教程

本文是综合了所有vue安装教程而成 更细化 更简略 希望对各位读者有所帮助&#xff01; Vue安装 1. Vue-cli脚手架安装 安装vue的方式有很多 我们这里选择npm方式安装vue npm方式 npm方式安装vue&#xff0c;详细介绍见下文。 1.node.js安装和配置 安装npm 需要安装note.js&…...

MySQL:约束constraint

约束就是表中数据的限制条件. 表在设计的时候加入约束的目的是为了保证表中记录的完整性和有效性&#xff0c;如用户表有些列的值&#xff08;手机号&#xff09;不能为空&#xff0c;有些列的值&#xff08;身份证号&#xff09;不能重复。 主键约束(primary key) PK MySQL主…...

使用Rufus制作Ubuntu需要注意

‌在使用Rufus制作Ubuntu启动盘并进行BIOS设置时&#xff0c;需要注意以下几点‌&#xff1a; ‌关闭RST&#xff08;英特尔 快速存储技术&#xff09;‌&#xff1a;在BIOS设置中&#xff0c;如果电脑启用了RST功能&#xff0c;需要将其关闭。因为Ubuntu可能无法检测到硬盘&a…...

探索Go语言的高级特性:性能分析与安全性

Go语言性能分析与安全性 引言 Go语言因其高效的并发特性、简洁的语法和强大的工具链而受到广泛欢迎。在实际开发中&#xff0c;性能分析和安全性是需要特别关注的两个方面。本文将深入探讨Go语言中的性能分析工具和安全性考虑&#xff0c;帮助开发者编写高效、安全的Go应用程…...

SearchSploit配合gcc的使用

渗透测试中&#xff0c;SearchSploit是一个非常有用的工具&#xff0c;用于在Exploit数据库中搜索漏洞利用代码。其使用方法如下&#xff1a; 安装SearchSploit&#xff1a;首先确保你的系统中已经安装了Kali Linux&#xff0c;因为SearchSploit是Kali Linux的一部分。如果没有…...

无人机设计:云台挂载!

一、无人机云台挂载设置 安装与固定 将云台固定到无人机的挂载点上&#xff0c;通常需要使用专用的固定架和螺丝等工具。 确保云台与无人机之间的连接牢固&#xff0c;避免在飞行过程中出现松动或脱落的情况。 连接与调试 将云台与无人机之间的连接线缆&#xff08;如电源…...

Spring Native适用场景、代理使用及测试部署策略

文章目录 1. Spring Native 适用的应用程序2. 在 Spring Native 中使用代理3. 测试和部署 Spring Native 应用测试部署 1. Spring Native 适用的应用程序 微服务&#xff1a;微服务架构中每个服务都相对独立&#xff0c;快速启动时间和较低的资源消耗对于提高部署效率和服务响…...

LeetCode—11. 盛最多水的容器(中等)

题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;…...

第一部分:入门准备 1.欢迎来到新手村 --[JavaScript 新手村:开启编程之旅的第一步]

为什么学习 JavaScript&#xff1f; 学习 JavaScript 有多个重要的理由&#xff0c;它在现代 Web 开发中扮演着不可或缺的角色。以下是几个关键原因&#xff1a; 1. 广泛的应用 JavaScript 是唯一可以在浏览器端直接运行的编程语言&#xff0c;几乎所有的网站和Web应用都使用…...

BERT的中文问答系统50

我们将对BERT的中文问答系统48-1代码进行以下改进: 1.增加时间日期和日历功能:在GUI中增加显示当前时间和日期的功能,并提供一个日历组件。 2.增加更多模型类型:增加娱乐、电脑、军事、汽车、植物、科技、历史(朝代、皇帝)、名人、生活(出行、菜品、菜谱、居家),法律、…...

深入解析CMake中的find_package命令:用法、特性及版本依赖问题

深入解析CMake中的find_package命令&#xff1a;用法、特性及版本依赖问题 在现代软件开发中&#xff0c;CMake作为一个强大的构建系统&#xff0c;广泛应用于跨平台项目的管理与编译。find_package是CMake中一个核心命令&#xff0c;用于查找并配置项目所依赖的外部库或包。本…...

【OpenDRIVE_Python】使用python脚本输出OpenDRIVE数据中含有隧道tunnel的道路ID和隧道信息

示例代码说明&#xff1a; 遍历OpenDRIVE数据中每条道路Road,若Road中存在隧道tunnel属性&#xff0c;则将该道路ID和包含的所有隧道信息输出到xml文件中。 import xml.dom.minidom from xml.dom.minidom import parse from xml.dom import Node import sys import os # 读取…...

SIP系列五:HTTP(SIP)鉴权

我的音视频/流媒体开源项目(github) SIP系列目录 目录 一、基本认证(basic) 二、摘要认证(digest) 1、摘要认证(digest) RFC 2069​ 2、摘要认证(digest) RFC 2617​ 2.1、未定义qop字段或值为"(空) 2.2、qop值为"auth" 2.3、qop值为"auth-int&quo…...

mysql json整数数组去重 整数数组精确查找并删除相应数据

都是针对整数数组 。低版本可用。懒得去查找资料的可以参考下。 json整数数组查找具体数据修改或者删除&#xff1a; update saas_new_tms.eda_logistics_limit set service_attribute json_remove(service_attribute,json_unquote(json_search(replace(service_attribute,…...

【5G】技术组件 Technology Components

5G的目标设置非常高&#xff0c;不仅在数据速率上要求达到20Gbps&#xff0c;在容量提升上要达到1000倍&#xff0c;还要为诸如大规模物联网&#xff08;IoT&#xff0c; Internet of Things&#xff09;和关键通信等新服务提供灵活的平台。这些高目标要求5G网络采用多种新技术…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

剑指offer20_链表中环的入口节点

链表中环的入口节点 给定一个链表&#xff0c;若其中包含环&#xff0c;则输出环的入口节点。 若其中不包含环&#xff0c;则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...