Chromium Chronicle #25: Anotasi Keamanan Thread

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

Di C++, mengesampingkan kemungkinan data race bergantung pada bukti ketepatan thread-safety yang kecil untuk setiap akses anggota data. Bukti ini dapat menimbulkan banyak pekerjaan mental, terutama saat meninjau atau memfaktorkan ulang kode. Framework analisis statis Clang mengambil alih kerja keras 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 diperlukan tetap aman, tetapi anotasi yang hilang dapat menimbulkan 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 memberlakukan pemeriksaan urutan

Sebagai imbalan untuk menganotasi anggota data, CLI akan memastikan bahwa metode apa pun yang mengakses data akan menjalankan pemeriksaan keamanan urutan sebelum melakukannya. Saat kode dipindahkan dalam pemfaktoran ulang, Clang akan 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 aman thread yang menggunakan mutex

Beberapa kelas 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 memberlakukan akuisisi kunci

Tunda dan biarkan compiler memastikan bahwa setiap base::AutoLock dicakupkan dengan benar, dan panggilan Acquire() serta Release() penguncian 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);
}