The Chromium Chronicle n. 25: annotazioni sulla sicurezza dei thread

Episodio 25: di Victor Costan in SFO (ottobre 2021)
Puntate precedenti

In C++, escludere la possibilità di corse di dati si riduce a una piccola prova di correttezza della sicurezza dei thread per ogni accesso ai membri dei dati. Queste prove comportano un grande lavoro mentale, soprattutto durante la revisione o il refactoring del codice. Il framework di analisi statico di Clang si occupa del faticoso processo di sicurezza dei thread.

Aggiungi GUARDED_BY_CONTEXT() ai membri dei dati nelle classi non sicure per i thread

La maggior parte delle classi di Chrome non è sicura per i thread e dovrebbe essere utilizzata in una singola sequenza. Aggiungere annotazioni a tutti i membri dei dati non compatibili con i thread. Le annotazioni non necessarie sono sicure, ma se quelle mancanti costituiscono un rischio di generazione di dati.

#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 applica i controlli sequenza

In cambio dell'annotazione dei membri dei dati, Clang garantisce che qualsiasi metodo che acceda ai dati esegua un controllo di sicurezza della sequenza prima di farlo. Man mano che il codice viene spostato durante il refactoring, Clang continua ad applicare l'annotazione 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);
}

Aggiungi GUARDED_BY() ai membri dei dati in classi thread-safe che utilizzano mutex

Alcuni corsi in Chrome devono utilizzare i blocchi per la sicurezza dei thread. In questi casi, annota tutti i membri di dati non compatibili con i thread. Ogni annotazione rimanda a un mutex che deve essere mantenuto premuto durante l'accesso al membro ai dati.

#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 applica le acquisizioni di blocchi

Resta in attesa e consenti al compilatore di assicurarsi che l'ambito di ogni base::AutoLock sia corretto e che le chiamate Acquire() e Release() di blocco siano accoppiate correttamente.

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