에피소드 25: 샌프란시스코의 Victor Costan (2021년 10월)
이전 에피소드
C++에서 데이터 경합의 가능성을 배제하는 것은 모든 데이터 멤버 액세스에 대한 작은 스레드 안전 정확성 증명에 달려 있습니다. 특히 코드를 검토하거나 리팩터링할 때 이러한 증거로 인해 많은 정신적 부담이 가중됩니다. Clang의 정적 분석 프레임워크가 스레드 안전 증명의 반복 업무를 대체합니다.
스레드 안전하지 않은 클래스의 데이터 멤버에 GUARDED_BY_CONTEXT()
를 추가합니다.
대부분의 Chrome 클래스는 스레드로부터 안전하지 않으며 단일 시퀀스에 사용해야 합니다. 스레드로부터 안전하지 않은 모든 데이터 멤버에 주석을 추가합니다. 불필요한 주석도 안전하지만 주석이 누락되면 데이터 경합이 발생할 위험이 있습니다.
#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에 시퀀스 검사 적용
Clang은 데이터 멤버에 주석을 추가하는 대신 데이터에 액세스하는 모든 메서드가 이렇게 하기 전에 시퀀스 안전 검사를 실행하도록 합니다. 리팩터링 중에 코드가 이동함에 따라 Clang은 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()
추가
Chrome의 일부 클래스는 스레드 안전을 위해 잠금을 사용해야 합니다. 이 경우 스레드로부터 안전하지 않은 모든 데이터 멤버에 주석을 달아야 합니다. 각 주석은 데이터 멤버에 액세스하는 동안 보유해야 하는 뮤텍스를 가리킵니다.
#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에서 잠금 획득 적용
잠시 후 컴파일러에서 각 base::AutoLock
의 범위가 올바르게 지정되고 잠금 Acquire()
및 Release()
호출이 올바르게 페어링되도록 합니다.
void ThreadSafeCache::Set(base::StringPiece key, base::StringPiece value) {
base::AutoLock auto_lock(lock_); // Clang warns without this.
data_.emplace(key, value);
}
- Chrome의 스레딩 및 태스크
- Clang 스레드 안전 분석: 더 복잡한 시나리오를 위한 다른 Clang 주석에 관해 알아보세요.