C++ 线程安全注解

实例开篇

线程安全注解是现代C++开发的机制,通常在编译期可以帮助发现一些线程安全问题。

下面直接从实例中来理解。

class Account {
private:Mutex mu;int money GUARDED_BY(mu);void Sub(int amount) {money -= amount;    // writing variable 'money' requires holding mutex 'mu' exclusively}void Add(int amount) REQUIRES(mu) {money += amount;}public:void Withdraw(int amount) {mu.Lock();Sub(amount);    // warning: mutex 'mu' is still held at the end of function}void Deposit(int amount) {mu.Lock();Add(amount);mu.Unlock();}void TransferFromOthers(Account& b, int amount) {mu.Lock();Sub(amount);b.Add(amount);  // calling function 'Add' requires holding mutex 'b.mu' exclusivelymu.Unlock();}
};

这段是一个账户的例子。

接口

向外暴露的接口为:

  • void Withdraw(int amount) 取款

    取款调用了 void Sub(int amount)

    而这里在 Withdraw 函数中也确实在调用 Sub 函数前已经持有锁 mu 了,但是这里并未对 Sub 函数添加 REQUIRES(mu) 注解,所以 Sub 函数本身不能保证在此已经持有锁 mu ,所以触发 Warning mutex 'mu' is still held at the end of function

    但是在 Sub 函数结束后,意味着需要释放锁,否则其他操作将无法获得锁 mu ,造成死锁问题。

  • void Deposit(int amount) 存款

    存款调用了 void Add(int amount)

    在进入 Add 函数前持有了锁 mu ,在从 Add 函数返回后也释放了锁 mu ,所以无报错。

    对于 Add 函数,其中添加了 REQUIRES(mu) 注解,如果存在某个调用 Add 的函数未在进入 Add 函数前持有锁 mu,则会在调用 Add 函数的部分触发 Warning calling function 'Add' requires holding mutex 'mu' exclusively 。如下代码所示

    void Deposit(int amount) {Add(amount); // calling function 'Add' requires holding mutex 'mu' exclusively
    }
    
  • void TransferToOthers(Account& b, int amount) 当前账号向账户 b 转账

    这个操作应该是个原子操作,这里先是减少当前账户余额,然后增加账户 b 的余额。

    Sub 需要加锁,加的是当前账户的锁 mu

    b.Add 也需要加锁,加的是账户 b 的锁 b.mu

    但是这里在进入 b.Add 函数前,当前函数并未持有锁 b.mu ,所以触发 Warning calling function 'Add' requires holding mutex 'b.mu' exclusively

如何修改呢,按照上述所述修改即可

private:Mutex mu;int money GUARDED_BY(mu);void Sub(int amount) REQUIRES(mu) {money -= amount;}void Add(int amount) REQUIRES(mu) {money += amount;}public:void Withdraw(int amount) {mu.Lock();Sub(amount);mu.Unlock();}void Deposit(int amount) {mu.Lock();Add(amount);mu.Unlock();}void TransferToOthers(Account& b, int amount) {mu.Lock();Sub(amount);b.mu.Lock();b.Add(amount);b.mu.Unlock();mu.Unlock();}
};

线程安全注解

这其中涉及到两个注解:

  • GUARDED_BY(mu) ,用于标识共享变量的保护互斥量。表示使用该变量时必须获得锁 mu
  • REQUIRES(mu) ,用于标识函数在调用时需要独占地持有指定的互斥量。表示进入该函数前必须获得锁 mu

在多线程编程中,当多个线程同时访问共享资源时,需要确保某些操作的执行是互斥的,即同一时间只能由一个线程执行。互斥操作通常涉及对共享资源的修改或对多个资源的原子性操作。

Mutex 定义

class LOCKABLE Mutex {
public:Mutex() = default;~Mutex() = default;Mutex(const Mutex&) = delete;Mutex& operator=(const Mutex&) = delete;void Lock() EXCLUSIVE_LOCK_FUNCTION() { mu_.lock(); }void Unlock() UNLOCK_FUNCTION() { mu_.unlock(); }void AssertHeld() ASSERT_EXCLUSIVE_LOCK() {}private:std::mutex mu_;
};

这里涉及到了四个注解:

  • LOCKABLE 一个自定义的宏定义或类型定义,表示这是一个可被加锁的类

  • EXCLUSIVE_LOCK_FUNCTION() 表示被标记的函数是一个独占锁函数,调用这个函数会获取一个独占锁。

  • UNLOCK_FUNCTION() 表示被标记的函数是一个解锁函数,调用这个函数会释放之前获取的独占锁。

  • ASSERT_EXCLUSIVE_LOCK() 表示被标记的函数用于断言当前线程持有一个独占锁,确保调用该函数的线程在调用时持有独占锁。

更多的线程安全注解,求STAR!!!

参考

  • 线程安全注解——GUARDED_BY

  • 【C++11高性能服务器】Thread Safety Analysis,概念,用法详解

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

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

相关文章

基于php+thinkphp+vue的校园二手交易网站

运行环境 开发语言:PHP 数据库:MYSQL数据库 应用服务:apache服务器 使用框架:ThinkPHPvue 开发工具:VScode/Dreamweaver/PhpStorm等均可 项目简介 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发…

43.241.18.123哪些问题会导致服务器里面时间错误

我们在使用服务器的过程中,有时候可能会发现,服务器里面时间跟标准的时间对不上,那服务器里面时间错误可能由哪些问题引起: 硬件问题:服务器硬件中的时钟或电池可能损坏或失效,导致时间不准确或重置为默认…

2024年计算机专业Java选题推荐✅(最新、最全、最容易通过的选择)

文章目录 前言选题和具体实现详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#x…

【LeetCode刷题(数据结构)】:对称二叉树

给你一个二叉树的根节点 root 检查它是否轴对称 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 提示&#xff1a; 树中节点数目在范围 [1, 1000] 内 -100 < Node.val < 100 对称二叉…

Aviator表达式引擎

一、快速介绍 &#xff08;一&#xff09;Aviator Aviator是一个用于动态表达式求值的高性能、轻量级Java引擎。以下是一些关于Aviator引擎的重要特点和设计目标&#xff1a; 轻量级和高性能&#xff1a; Aviator的设计目标之一是轻量级和高性能。它的大小很小&#xff0c;加…

PyQt中线程和线程信号的使用

PyQt中的线程和线程信号是用于在应用程序中实现多线程编程的重要概念。线程允许你在应用程序中同时执行多个任务&#xff0c;而线程信号用于在不同线程之间进行通信和协调。以下是关于PyQt中线程和线程信号的简要解释&#xff1a; 线程&#xff1a; 线程是应用程序中的并发执行…

@Component 和 @Bean的区别

Component 和 Bean 是Spring框架中用于管理和配置依赖注入的关键注解&#xff0c;用于定义和管理Spring应用程序中的组件。 Component: Component 是一种泛用型的Spring注解&#xff0c;用于标识一个类为Spring组件。Spring会自动扫描所有带有Component 注解的类&#xff0c;并…

介绍一下mysql有哪些索引类型

以下是MySQL的8种不同索引类型的比较&#xff0c;以帮助你了解它们的特点和适用场景&#xff1a; 索引类型用途和特点适用场景B-Tree 索引用于范围查询、等值查找和排序操作大多数查询 &#xff0c;不适合全文搜索和空间数据。唯一索引保证索引列的值唯一&#xff0c;不允许重…

PTA程序辅助设计平台—2023年软件设计综合实践_4(数组及字符串)

6-1 找最小元素/选择排序 - C/C 数组及字符串 &#xff08;找最小元素&#xff09;对于给定的包含10个元素的整数数组&#xff0c;设计一个函数&#xff0c;从数组给定的下标范围[i,j]里找到值最小的元素&#xff0c;返回其下标。该函数的原型可以是int findMin(int a[], int …

【Redis】Java客户端使用list命令

lpush/lrange rpush/rpop/lpop blpop/brpop llen

mac使⽤nginx

⽅法1&#xff1a;homebrew 默认本地已经安装homebrew&#xff1b; 安装与启动 brew install nginx 安装nginx&#xff1b; brew services start nginx 启动nginx nginx⽂件⽬录 1. nginx安装⽂件⽬录/usr/local/Cellar/nginx 2. nginx配置⽂件⽬录/usr/local/etc/nginx 3. con…

Windows 多媒体编程库 DirectX 介绍

目录 1、什么是DirectX&#xff1f; 2、使用DirectX的好处 2.1、DirectX为软件开发者提供硬件无关性 2.2、为硬件开发提供策略 3、DirectX的主体构成 3.1、Direct3D 3.2、DirectDraw 3.3、DirectPlay 3.4、DirectSound 3.5、DirectMusic 3.6、DirectInput 4、Dire…

谈谈多线程与多线程同步

一、线程展开说说 二、走近多线程同步

uniapp快速入门系列(4)- 微信小程序开发

第四章 微信小程序开发 4.1 微信小程序开发与uniapp的融合4.2 微信小程序API在uniapp中的使用4.3 微信小程序常见问题的解决方法问题1: 如何获取用户信息&#xff1f;问题2: 如何获取当前位置&#xff1f;问题3: 如何发送网络请求&#xff1f; 在本章中&#xff0c;我们将学习如…

缓存降级代码结构设计

缓存降级设计思想 接前文缺陷点 本地探针应该增加计数器&#xff0c;多次异常再设置&#xff0c;避免网络波动造成误判。耦合度过高&#xff0c;远端缓存和本地缓存应该平行关系被设计为上下游关系了。公用的远端缓存的操作方法应该私有化&#xff0c;避免集成方代码误操作&…

lvgl 界面管理器

lv_scr_mgr lvgl 界面管理器 适配 lvgl 8.3 降低界面之间的耦合使用较小的内存&#xff0c;界面切换后会自动释放内存内存泄漏检测 使用方法 在lv_scr_mgr_port.h 中创建一个枚举&#xff0c;用于界面ID为每个界面创建一个页面管理器句柄将界面句柄添加到 lv_scr_mgr_por…

机器学习基础之《回归与聚类算法(2)—欠拟合与过拟合》

一、背景 1、上一篇说正规方程的时候&#xff0c;实际情况中使用很少&#xff0c;主要原因它不能解决过拟合。 2、训练集上表现的好&#xff0c;测试集上表现不好—过拟合 二、欠拟合和过拟合 1、欠拟合 训练集&#xff1a;有3个训练集&#xff0c;告诉机器都是天鹅 机器学…

Docker 构建Python镜像时,pip使用国内地址的dockerfile模版

一、问题现象 构建镜像时&#xff0c;使用pip命令打包报错&#xff1a; 二、问题根因 因国内无法访问pip的配置文件中的仓库地址 三、解决办法 这个办法同样适用于&#xff1a;物理机&#xff0c;这个地址是阿里云的 pip config set global.index-url http://mirrors.aliy…

WebAPI+EF连接SQL Server数据库

右击解决方案-添加-新建项目-选择“类库&#xff08;.NET Framework&#xff09;”,新建的项目取名叫WebApi1.EF 添加EF&#xff1a; 新建一个ADO实体数据模型 选择DBFirst 数据源选择MySql 填写数据库地址及账号密码 选择实体框架版本 选择在数据库中的表User 到此配置完成&am…

稚晖君项目复刻:L-ink门禁卡(1)——环境搭建与第一个项目创建

行文目录 前言其他文章正文开始STM32CubeMX安装STM32CubeMX安装L0的固件支持包Clion安装OpenOCD安装MinGw安装arm-none-eabi-gcc安装Clion配置 创建STM32工程创建STM32CubeMX工程更改芯片型号 参考文献 前言 其实关于稚晖君的L-ink门禁卡在我本科阶段就已经刷过好几次了&#x…