Chromium Chronicle Nr. 25: Sicherheitshinweise für Threads

Folge 25:von Victor Costan auf SFO (Oktober 2021)
Vorherige Folgen

Wenn in C++ mögliche Datenrennen ausgeschlossen werden, reicht ein kleiner Nachweis der Threadsicherheit bei jedem Datenzugriff aus. Diese Beweise bedeuten eine Menge Arbeit, insbesondere bei der Überprüfung oder Refaktorierung von Code. Das statische Analyse-Framework von Clang übernimmt die mühsame Arbeit von Beweisen zur Threadsicherheit.

GUARDED_BY_CONTEXT() zu Datenmitgliedern in Threads-unsicheren Klassen hinzufügen

Die meisten Chrome-Klassen sind nicht sicher und sollten für eine einzelne Sequenz verwendet werden. Fügen Sie allen Datenmitgliedern, die nicht Thread-sicher sind, Annotationen hinzu. Unnötige Anmerkungen sind sicher. Fehlende Annotationen führen jedoch zu Datenrennen.

#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 erzwingt Sequenzprüfungen

Als Annotierung der Datenelemente sorgt Clang dafür, dass jede Methode, die auf die Daten zugreift, vorher eine Sequenzsicherheitsprüfung durchführt. Wenn der Code im Rahmen von Refaktorierungen verschoben wird, erzwingt Clang weiterhin die Annotation 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() zu Datenmitgliedern in Thread-sicheren Klassen hinzufügen, die Mutexe verwenden

Einige Klassen in Chrome müssen Sperren für die Threadsicherheit verwenden. Annotieren Sie in diesen Fällen alle Datenmitglieder, die nicht Thread-sicher sind. Jede Annotation verweist auf einen Mutex, der beim Zugriff auf das Datenmitglied gehalten werden muss.

#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 erzwingt das Abrufen von Sperren

Warten Sie einen Moment und lassen Sie den Compiler prüfen, ob jeder base::AutoLock-Bereich korrekt begrenzt ist und ob Sperraufrufe Acquire() und Release() korrekt gekoppelt sind.

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