代码改变世界

c++的线程安全静态检查 Thread Safety Analysis

2022-12-02 20:54  youxin  阅读(273)  评论(0编辑  收藏  举报

leveldb源码的过程中,发现很多成员变量被GUARDED_BY修饰,如下:

struct IterState {
  port::Mutex* const mu;
  Version* const version GUARDED_BY(mu);
  MemTable* const mem GUARDED_BY(mu);
  MemTable* const imm GUARDED_BY(mu);

  IterState(port::Mutex* mutex, MemTable* mem, MemTable* imm, Version* version)
      : mu(mutex), version(version), mem(mem), imm(imm) {}
};

宏定义如下:

 

#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x)  // no-op
#endif

#endif  // !defined(THREAD_ANNOTATION_ATTRIBUTE__)

#ifndef GUARDED_BY
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#endif

#ifndef PT_GUARDED_BY
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#endif

通过翻阅资料,发现这是c++静态检测对应的变量是否有对应的mutex保护的方法。

只要在代码中通过代码注解(annotations )告诉编译器哪些成员变量和成员函数是受哪个 mutex 保护,这样如果忘记了加锁,编译器会给警告。因为在后续维护别人的代码时候,往往不像原作者那样深刻理解设计意图,特别容易遗漏线程安全的假设。

使用方法也很简单,我们可以通过clang增加编译参数-Wthread-safety -Werror,获取有关线程安全的warning。

而leveldb使用的是abseil-cpp版本,使用方法相同
————————————————

 

总览
Thread Safety Analysis
线程安全分析的工作原理非常类似于多线程程序的类型系统。除了声明数据类型(例如int、float等)之外,程序员还可以(选择性地)声明如何在多线程环境中控制对数据的访问。例如,如果foo是由互斥锁mu保护的,那么当一段代码在没有首先锁定mu的情况下对foo进行读写时,分析就会发出警告。类似地,如果有一些特定的例程应该只由GUI线程调用,那么分析将在其他线程调用这些例程时发出警告。
————————————————

主要宏一览 

GUARDED_BY(mu)    数据成员收到mu保护,读共享,写排他(即写前锁)
REQUIRES(mu)    调用函数或方法前,需要mu,即函数进入前已持有,退出后仍持有
ACQUIRE(mu)    调用函数或方法时,持有mu,即函数进入时才持有,退出后不释放
RELEASE(mu)    调用函数或方法时,释放mu,即函数进入前已持有,退出前释放
EXCLUDES(mu)    调用函数或方法时,不需mu,即函数进入前不能持有,退出后自然不能释放
NO_THREAD_SAFETY_ANALYSIS    调用函数或方法时,关闭对其线程安全检查
RETURN_CAPABILITY(mu)    **声明函数返回对给定能力的引用,**用于注释返回互斥对象的getter方法。
CAPABILITY(<string>)    指定**类的对象(this)**可以作为能力使用,配合无参数ACQUIRE和RELEASE使用
SCOPE_CAPABILITY    实现RAII-style锁的类的一个属性,其功能在构造函数中获得,在析构函数中释放
TRY_ACQUIRE<bool,mu>    试图获得给定的功能,并返回一个指示成功或失败的布尔值。
ASSET_CAPABILITY(mu)    它断言调用线程已经拥有给定的能力
————————————————

  • 其余关键组合词(如ACQUIRE与ACQUIRE_SHARED)
    • PT pointer
    • SHARED 支持共享访问
    • GENERIC 支持独占和共享访问


入门实操
通过代码注解(annotations)告诉编译器哪些成员变量和成员函数受mutex保护,若忘记加锁,编译器给出警告。
目的:
他人后续维护代码时,特别容易遗漏线程安全的假设。此工具能将原作者设计意图以代码注解清楚地写出来并让编译器【自动检查】!
注意:

GUARDED_BY 表明哪个成员变量被mutex保护
clang-Wthead-safety编译代码
————————————————
版权声明:本文为CSDN博主「紫菜花油菜花」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42157432/article/details/115939656

 

 


参考:https://blog.csdn.net/zxpoiu/article/details/115963687

https://blog.csdn.net/weixin_42157432/article/details/115939656