Chromium Chronicle #25:线程安全注解

第 25 集:由 Victor Costan 在 SFO 中发表(2021 年 10 月)
上一集

在 C++ 中,排除数据争用的可能性取决于每个数据成员访问的小型线程安全正确性证明。这些证据加起来需要付出大量的精力,尤其是在审核或重构代码时。Clang 的静态分析框架取代了费力的线程安全证明

向线程不安全类中的数据成员添加了 GUARDED_BY_CONTEXT()

大多数 Chrome 类都是线程不安全的,应在单个序列中使用。向所有非线程安全数据成员添加注解。 不必要的注解是安全的,但缺少注解可能会导致数据争用。

#include "base/sequence_checker.h"  // for SEQUENCE_CHECKER()
#include "base/thread_annotations.h"  // for GUARDED_BY_CONTEXT()

class Cache {
  // Methods here.
 private:
  SEQUENCE_CHECKER(sequence_checker_);
  base::flat_map<std::string, std::string> data_ GUARDED_BY_CONTEXT(sequence_checker_);
};

Clang 强制执行顺序检查

为了给数据成员添加注解,Clang 会确保任何访问数据的方法会先执行序列安全检查,然后再执行该操作。随着代码在重构过程中移动,Clang 继续强制执行 GUARDED_BY_CONTEXT() 注解。

void Cache::Set(base::StringPiece key, base::StringPiece value) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);  // Clang warns without this.
  data_.emplace(key, value);
}

向使用互斥的线程安全类中的数据成员添加了 GUARDED_BY()

Chrome 中的某些类必须使用锁以确保线程安全。在这些情况下,请为所有非线程安全的数据成员添加注解。每个注解都指向访问数据成员时必须保留的互斥。

#include "base/thread_annotations.h"  // for GUARDED_BY()

class ThreadSafeCache {
  // Methods here.
  private:
    base::Lock lock_;
    base::flat_map<std::string, std::string> data_ GUARDED_BY(lock_);
};

Clang 强制执行锁获取

挂起并让编译器确保正确设置了每个 base::AutoLock 的作用域,并确保锁定 Acquire()Release() 调用正确配对。

void ThreadSafeCache::Set(base::StringPiece key, base::StringPiece value) {
  base::AutoLock auto_lock(lock_);  // Clang warns without this.
  data_.emplace(key, value);
}