本文内容来自 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. oracle删除表空间和用户

    步骤一: 删除tablespace(登录对应用户删除表空间) DROP TABLESPACE tablespace_name INCLUDING CONTENTS AND DATAFILES; 步骤二 ...

  2. 基于tornado---异步并发接口

    1.目的 由于有多个程序和脚本需要对mysql进行读写数据库,每次在脚本中进行数据库的连接.用cursor进行操作过于麻烦,因此希望可以有一个脚本开放接口,只需要传入sql语句,就可以返回结果回来.因 ...

  3. 【实战3】记一次内网中反弹shell的艰难历程

    # 0x00 前言 最近在客户现场对内网服务器进行渗透测试,发现了大量的弱口令,本次历程就是从这里开始··· # 0x01 弱口令 对目标ip进行端口扫描,开放端口为80,445,1433,3389- ...

  4. [AI] 切换cuda版本的万金油

    1. 环境 ubuntu16.04 GTX1080Ti x 4 nvidia-418 cuda-10.1 pytorch1.0.0 目标:在最新的显卡驱动下,使用不同版本的cuda和深度学习框架来执行 ...

  5. Python使用request包请求网页乱码解决方法

    使用requests请求网页时,返回的页面信息有时是乱码,如下代码 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) App ...

  6. poj3974 Palindrome(Manacher最长回文)

    之前用字符串hash+二分过了,今天刚看了manacher拿来试一试. 这manacher也快太多了%%% #include <iostream> #include <cstring ...

  7. oracle数据库(四)

    子查询与高级查询 我们在检索数据库的时候,需要将多个表关联起来进行查询,最常用的有子查询.连接查询和集合查询,子查询可以从另外一个表获取数据,连接查询可以指定多个表的连接方式,集合查询可以将两个或者多 ...

  8. Linux操作系统性能调优的方法

    http://www.cnblogs.com/L-H-R-X-hehe/p/3963442.html Linux是一套免费使用和自由传播的类Unix操作系统,Linux不同的发行版本和不同的内核对各项 ...

  9. DNS隧道

    自己使用的dns隧道通过两种方法,一种是通过dnscat2工具,另一种通过cs上的beacon来进行通信. 第一种方法:dnscat2: 参考文章:https://xz.aliyun.com/t/22 ...

  10. OLED液晶屏幕(1)OLED液晶屏幕ssd1306驱动芯片 arduino运行 ESP8266-07可以 12f不可以

    OLED屏幕有各种形状和尺寸,但目前有两种非常受欢迎的屏幕尺寸. 1)0.96“ 2)1.3“ 他们也有2种常见的颜色 1)蓝色 2)白色 驱动OLED的芯片常用的有两种.这两种芯片有许多非常相似的设 ...