本文内容来自 Thread Safety Analysis,如需完整学习,请参考相关链接。

Clang线程安全分析工具是C++语言的一种扩展,用于警告代码中潜在的竞争条件。它在编译期间进行静态分析,无运行期性能损耗。即使该工具仍处在开发阶段,但已足够成熟,适合部署在生产环境上。

它的工作原理类似于一个针对多线程编程的类型系统。例如,变量 foo可被多线程访问,当分析工具检测到该变量在读写时没有被对应的锁所保护时,会提示一个警告。

基本概念

clang的线程安全分析工具使用capabilities来保护资源。这里的资源指的是成员数据,或者是提供访问底层资源的函数或方法。它能确保调用线程只有先拥有capability,才能访问对应资源。

假如 mu 代表一个 mutex ,当线程执行 mu.Lock() 后,代表它获得了访问 mu 所保护资源的 capability ,当它调用 mu.unLock() 后,代表它释放了该 capability。该线程拥有的capability是不可拷贝的,也不能销毁它,它只能释放该capability,以便其他线程获得该capability

使用方法

线程安全分析工具使用属性注解来声明依赖,这些属性注解是附加在类、方法、数据成员之上的。官方推荐使用宏(mutex.h)来使属性注解可读性更好、可理解。

运行方法很简单,执行

clang -c -Wthread-safety example.cpp

适用于变量的注解

  • GUARDED_BY: 该属性声明,线程在对该变量进行读写之前,一定要获得对应的锁,以确保对该变量的操作是线程安全的。

  • PT_GUARDED_BY: 和GUARDED_BY类似,它用于指针和智能指针上,对指针自身没有约束,但对它所指向的数据施加属性保护。

Mutex mu;
int *p1 GUARDED_BY(mu);
int *p2 PT_GUARDED_BY(mu);
unique_ptr<int> p3 PT_GUARDED_BY(mu); void test() {
p1 = 0; // Warning! *p2 = 42; // Warning!
p2 = new int; // OK. *p3 = 42; // Warning!
p3.reset(new int); // OK.
}

适用于函数的注解

  • REQUIRES(mu) 指示调用线程在调用该函数前,必须先获得mu锁。它假设调用者在调用该函数前,已经拥有mu锁,内部对共享变量的修改无需额外加锁。

  • REQUIRES_SHARED(), 与 REQUIRES 类似,但仅要求共享读访问权限。

Mutex mu1, mu2;
int a GUARDED_BY(mu1);
int b GUARDED_BY(mu2); void foo() REQUIRES(mu1, mu2) {
a = 0;
b = 0;
} void test() {
mu1.Lock();
foo(); // Warning! Requires mu2.
mu1.Unlock();
}
  • ACQUIRE() 声明要求函数内部获得锁,直到退出该函数也无需释放它。调用者在调用该函数前,不能持有该锁。
  • RELEASE() 声明函数具备释放锁的能力,调用者在调用入口处无需持有该锁,函数退出前会主动释放该锁。
Mutex mu;
MyClass myObject GUARDED_BY(mu); void lockAndInit() ACQUIRE(mu) {
mu.Lock();
myObject.init();
} void cleanupAndUnlock() RELEASE(mu) {
myObject.cleanup();
} // Warning! Need to unlock mu. void test() {
lockAndInit();
myObject.doSomething();
cleanupAndUnlock();
myObject.doSomething(); // Warning, mu is not locked.
}

如果没有参数传递给 ACQUIRE 或 RELEASE,则假定入参为 this ,分析工具不会检查函数内部实现。常用在隐藏抽象接口的内部锁的实现细节。

  • EXCLUDES(...) 声明调用者不能持有给定 capabilities, 该注解用来预防死锁,对于不可重入的锁,当同一个函数重入时,会获得2次锁,造成死锁。
Mutex mu;
int a GUARDED_BY(mu); void clear() EXCLUDES(mu) {
mu.Lock();
a = 0;
mu.Unlock();
} void reset() {
mu.Lock();
clear(); // Warning! Caller cannot hold 'mu'.
mu.Unlock();
}
  • NO_THREAD_SAFETY_ANALYSIS: 关闭线程安全检查,该属性不属于声明的一部分,使用时要放在 .cpp 文件中。

适用于类的注解

  • CAPABILITY(): 指明该类的实例可被用作 capaility,string参数用来表明该 capaility 的种类,在警告时会输出。

  • SCOPED_CAPABILITY:指明该类用于RAII风格的资源管理。

Clang的线程安全分析静态工具的更多相关文章

  1. clang的线程安全分析模块 thread safety analysis

    介绍 Clang的线程安全分析模块是C++语言的一个扩展,能对代码中潜在的竞争条件进行警告.这种分析是完全静态的(即编译时进行),没有运行时的消耗.当前这个功能还在开发中,但它已经具备了足够的成熟度, ...

  2. java线程dump分析工具

    jstack和线程dump分析  java程序性能分析之thread dump和heap dump 一.[内存dump] jmap –dump:live,format=b,file=heap.bin ...

  3. 【转】java线上程序排错经验2 - 线程堆栈分析

    前言 在线上的程序中,我们可能经常会碰到程序卡死或者执行很慢的情况,这时候我们希望知道是代码哪里的问题,我们或许迫切希望得到代码运行到哪里了,是哪一步很慢,是否是进入了死循环,或者是否哪一段代码有问题 ...

  4. Linux性能分析命令工具汇总

    转自:http://rdc.hundsun.com/portal/article/731.html?ref=myread 出于对Linux操作系统的兴趣,以及对底层知识的强烈欲望,因此整理了这篇文章. ...

  5. (转)java线程安全问题之静态变量、实例变量、局部变量

    java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定义,如 ...

  6. Spring中获取request的几种方法,及其线程安全性分析

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...

  7. [No000016E]Spring 中获取 request 的几种方法,及其线程安全性分析

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...

  8. java线程安全问题之静态变量、实例变量、局部变量

    java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定义,如 ...

  9. Spring中获取request的几种方法,及其线程安全性分析(山东数漫江湖)

    前言 本文将介绍在Spring MVC开发的web系统中,获取request对象的几种方法,并讨论其线程安全性. 原创不易,如果觉得文章对你有帮助,欢迎点赞.评论.文章有疏漏之处,欢迎批评指正. 欢迎 ...

随机推荐

  1. Pthon魔术方法(Magic Methods)-上下文管理

    Pthon魔术方法(Magic Methods)-上下文管理 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.上下文管理方法 __enter__: 进入与此对象相关的上下文.如果 ...

  2. 泛微 e-cology OA 远程代码执行漏洞复现

    0x00 前言 Poc已在github公开,由于环境搭建较为复杂,所以我在空间搜索引擎中找了国外的网站进行复现 如果有想自行搭建环境复现的可以在公众号内回复“泛微环境”即可获取源码及搭建方式 0x01 ...

  3. jquery选择器之全选择器

    在CSS中,经常会在第一行写下这样一段样式 * {padding: 0; margin: 0;} 通配符*意味着给所有的元素设置默认的边距.jQuery中我们也可以通过传递*选择器来选中文档页面中的元 ...

  4. Cisco网络模拟器踩坑记录

    1.在我们新建一个拓扑图的时候,选择设备之间的连线种类有时会导致线路不通的情况(两个端口上为红色点)这时候建议拆除这条线后选择闪电标记 的万能线帮助我们自动创建连线(这时就能根据它显示的线条种类得知应 ...

  5. SOA 架构与微服务架构的区别

    注重重用,微服务注重重写 SOA 的主要目的是为了企业各个系统更加容易地融合在一起. 微服务通常由重写一个模块开始.要把整个巨石型的应用重写是有很大的风险的,也不一定必要.我们向微服务迁移的时候通常从 ...

  6. PHP隐藏IP地址末位的方法

    很久之前写过一个使用ASP隐藏IP地址末位的文章,也就是有时候为了保护用户的隐私,会隐藏用户的IP地址,达成类似于 222.222.222.* 的效果.  现在想要用PHP来实现,经过尝试,其实非常简 ...

  7. CSE301 – Bio-Computation

    CSE301 – Bio-Computation Assessment 3Contribution to overall module assessment 10%Submission deadlin ...

  8. C++中继承 声明基类析构函数为虚函数作用,单继承和多继承关系的内存分布

    1,基类析构函数不为虚函数 #include "pch.h" #include <iostream> class CBase { public: CBase() { m ...

  9. shell脚本编程基础之case语句

    基础简介 脚本编程分为: 面向过程 选择结构:if语句,单分支.双分支.多分支:case语句 控制结构:顺序结构(默认) 循环结构:for.while.until 面向对象 case语句结构 case ...

  10. Connection to newtaotao failed. [08001] Could not create connection to database

    jdbc.url=jdbc:mysql://localhost:3306/newtaotao?serverTimezone=UTC&characterEncoding=utf-8 数据库是5. ...