Clang的線程安全分析靜態工具

本文內容來自 Thread Safety Analysis,如需完整學習,請參考相關連接。html

Clang線程安全分析工具是C++語言的一種擴展,用於警告代碼中潛在的競爭條件。它在編譯期間進行靜態分析,無運行期性能損耗。即便該工具仍處在開發階段,但已足夠成熟,適合部署在生產環境上。編程

它的工做原理相似於一個針對多線程編程的類型系統。例如,變量 foo可被多線程訪問,當分析工具檢測到該變量在讀寫時沒有被對應的鎖所保護時,會提示一個警告。安全

基本概念

clang的線程安全分析工具使用capabilities來保護資源。這裏的資源指的是成員數據,或者是提供訪問底層資源的函數或方法。它能確保調用線程只有先擁有capability,才能訪問對應資源。多線程

假如 mu 表明一個 mutex ,當線程執行 mu.Lock() 後,表明它得到了訪問 mu 所保護資源的 capability ,當它調用 mu.unLock() 後,表明它釋放了該 capability。該線程擁有的capability是不可拷貝的,也不能銷燬它,它只能釋放該capability,以便其餘線程得到該capability函數

使用方法

線程安全分析工具使用屬性註解來聲明依賴,這些屬性註解是附加在類、方法、數據成員之上的。官方推薦使用宏(mutex.h)來使屬性註解可讀性更好、可理解。工具

運行方法很簡單,執行性能

clang -c -Wthread-safety example.cpp

適用於變量的註解

  • GUARDED_BY: 該屬性聲明,線程在對該變量進行讀寫以前,必定要得到對應的鎖,以確保對該變量的操做是線程安全的。學習

  • PT_GUARDED_BY: 和GUARDED_BY相似,它用於指針和智能指針上,對指針自身沒有約束,但對它所指向的數據施加屬性保護。ui

Mutex mu;
int *p1             GUARDED_BY(mu);
int *p2             PT_GUARDED_BY(mu);
unique_ptr<int> p3  PT_GUARDED_BY(mu);

void test() {
  p1 = 0;             // Warning!

  *p2 = 42;           // Warning!
  p2 = new int;       // OK.

  *p3 = 42;           // Warning!
  p3.reset(new int);  // OK.
}

適用於函數的註解

  • REQUIRES(mu) 指示調用線程在調用該函數前,必須先得到mu鎖。它假設調用者在調用該函數前,已經擁有mu鎖,內部對共享變量的修改無需額外加鎖。this

  • REQUIRES_SHARED(), 與 REQUIRES 相似,但僅要求共享讀訪問權限。

Mutex mu1, mu2;
int a GUARDED_BY(mu1);
int b GUARDED_BY(mu2);

void foo() REQUIRES(mu1, mu2) {
  a = 0;
  b = 0;
}

void test() {
  mu1.Lock();
  foo();         // Warning!  Requires mu2.
  mu1.Unlock();
}
  • ACQUIRE() 聲明要求函數內部得到鎖,直到退出該函數也無需釋放它。調用者在調用該函數前,不能持有該鎖。
  • RELEASE() 聲明函數具有釋放鎖的能力,調用者在調用入口處無需持有該鎖,函數退出前會主動釋放該鎖。
Mutex mu;
MyClass myObject GUARDED_BY(mu);

void lockAndInit() ACQUIRE(mu) {
  mu.Lock();
  myObject.init();
}

void cleanupAndUnlock() RELEASE(mu) {
  myObject.cleanup();
}                          // Warning!  Need to unlock mu.

void test() {
  lockAndInit();
  myObject.doSomething();
  cleanupAndUnlock();
  myObject.doSomething();  // Warning, mu is not locked.
}

若是沒有參數傳遞給 ACQUIRE 或 RELEASE,則假定入參爲 this ,分析工具不會檢查函數內部實現。經常使用在隱藏抽象接口的內部鎖的實現細節。

  • EXCLUDES(...) 聲明調用者不能持有給定 capabilities, 該註解用來預防死鎖,對於不可重入的鎖,當同一個函數重入時,會得到2次鎖,形成死鎖。
Mutex mu;
int a GUARDED_BY(mu);

void clear() EXCLUDES(mu) {
  mu.Lock();
  a = 0;
  mu.Unlock();
}

void reset() {
  mu.Lock();
  clear();     // Warning!  Caller cannot hold 'mu'.
  mu.Unlock();
}
  • NO_THREAD_SAFETY_ANALYSIS: 關閉線程安全檢查,該屬性不屬於聲明的一部分,使用時要放在 .cpp 文件中。

適用於類的註解

  • CAPABILITY( ): 指明該類的實例可被用做 capaility,string參數用來代表該 capaility 的種類,在警告時會輸出。

  • SCOPED_CAPABILITY:指明該類用於RAII風格的資源管理。

相關文章
相關標籤/搜索