Chromium Chronicle #25: Chú thích an toàn cho chuỗi

Tập 25: của Victor Costan tại SFO (tháng 10 năm 2021)
Các tập trước

Trong C++, việc loại trừ khả năng chạy đua dữ liệu sẽ dẫn đến một bằng chứng nhỏ về độ chính xác về độ an toàn của luồng cho mọi quyền truy cập của thành viên dữ liệu. Những bằng chứng này sẽ tiêu tốn rất nhiều công sức, đặc biệt là khi xem xét hoặc tái cấu trúc mã. Khung phân tích tĩnh của Clang xử lý rất nhiều bằng chứng về độ an toàn của chuỗi.

Thêm GUARDED_BY_CONTEXT() vào thành phần dữ liệu trong các lớp không an toàn cho luồng

Hầu hết các lớp Chrome đều không an toàn theo luồng và nên được dùng trên một trình tự duy nhất. Thêm chú thích cho tất cả thành phần dữ liệu không an toàn cho luồng. Các chú thích không cần thiết vẫn an toàn, nhưng việc thiếu chú thích sẽ có nguy cơ gây ra các cuộc chạy đua dữ liệu.

#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 thực thi quy trình kiểm tra trình tự

Để chú thích các thành phần dữ liệu, Clang đảm bảo rằng mọi phương thức truy cập vào dữ liệu đều thực hiện kiểm tra an toàn theo trình tự trước khi thực hiện việc này. Khi mã được di chuyển trong quá trình tái cấu trúc, Clang tiếp tục thực thi chú thích 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);
}

Thêm GUARDED_BY() vào thành phần dữ liệu trong các lớp an toàn cho luồng có sử dụng mutex

Một số lớp trong Chrome phải sử dụng khoá để đảm bảo an toàn cho chuỗi. Trong những trường hợp này, hãy chú thích mọi thành phần dữ liệu không an toàn cho luồng. Mỗi chú thích trỏ đến một mutex phải được giữ khi truy cập vào thành phần dữ liệu.

#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 thực thi việc mua lại khoá

Hãy đợi và để trình biên dịch đảm bảo rằng mỗi base::AutoLock được xác định phạm vi chính xác, đồng thời khoá các lệnh gọi Acquire()Release() được ghép nối đúng cách.

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