Chromium Chronicle #25: Аннотации по безопасности потоков

Эпизод 25: Виктор Костан в SFO (октябрь 2021 г.)
Предыдущие серии

В 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);
}