Chromium Chronicle #25: Anotasi Keamanan Thread

Episode 25: oleh Victor Costan dalam SFO (Oktober 2021)
Episode sebelumnya

Dalam C++, mengesampingkan kemungkinan data race bermuara pada bukti kebenaran thread-safety yang kecil untuk setiap akses anggota data. Bukti ini menambah banyak upaya mental, terutama saat meninjau atau memfaktorkan ulang kode. Framework analisis statis Clang menggantikan toil bukti keamanan thread.

Menambahkan GUARDED_BY_CONTEXT() ke anggota data di class yang tidak aman untuk thread

Sebagian besar class Chrome tidak aman untuk thread, dan harus digunakan dalam satu urutan. Menambahkan anotasi ke semua anggota data yang tidak aman untuk thread. Anotasi yang tidak perlu akan aman, tetapi anotasi yang tidak ada dapat menjadi risiko data race.

#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 menerapkan pemeriksaan urutan

Sebagai imbalan untuk menganotasi anggota data, Clang memastikan bahwa setiap metode yang mengakses data melakukan pemeriksaan keamanan urutan sebelum melakukannya. Saat kode dipindahkan dalam pemfaktoran ulang, Clang terus menerapkan anotasi 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);
}

Menambahkan GUARDED_BY() ke anggota data di class yang aman untuk thread yang menggunakan mutex

Beberapa class di Chrome harus menggunakan kunci untuk keamanan thread. Dalam kasus ini, anotasikan semua anggota data yang tidak aman untuk thread. Setiap anotasi mengarah ke mutex yang harus ditahan saat mengakses anggota data.

#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 menerapkan akuisisi kunci

Hang back dan biarkan compiler memastikan bahwa setiap base::AutoLock dicakup dengan benar, dan panggilan kunci Acquire() dan Release() akan disambungkan dengan benar.

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