티스토리 뷰

카테고리 없음

Thread Safety Analysis

newpolaris 2020. 2. 1. 19:45

https://clang.llvm.org/docs/ThreadSafetyAnalysis.html

clang TSA (thread safety analysis) for C (not just C++)

https://github.com/jhi/clang-thread-safety-analysis-for-c/blob/master/tsa.h

newpolaris@Donghyuns-MacBook-Pro test2 % clang++ -Wthread-safety main.cpp --std=c++14 -stdlib=libc++
main.cpp:7:17: warning: 'guarded_by' attribute requires arguments whose type is annotated with 'capability' attribute;
      type here is 'std::mutex' [-Wthread-safety-attributes]
    int balance GUARDED_BY(mu);
                ^
./mutex.h:21:33: note: expanded from macro 'GUARDED_BY'
  THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
                                ^
main.cpp:10:9: warning: writing variable 'balance' requires holding mutex 'mu' exclusively [-Wthread-safety-analysis]
        balance -= amount;

clang 최신 버전에는 std 함수에도 반영되었다고 하는데 왜 저럴까?

mutex 소스에는 해당 처리가 되어있다, 하지만 define 등으로 guard 되어있는데,

#define _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS

#include <mutex>

newpolaris@Donghyuns-MacBook-Pro test2 % clang++ -Wthread-safety main.cpp --std=c++11 
main.cpp:10:9: warning: writing variable 'balance' requires holding mutex 'mu' exclusively [-Wthread-safety-analysis]
        balance -= amount;

해당 define을 추가하면 동작은 한다

benchmark의 예제를 보면,

// NOTE: Wrappers for std::mutex and std::unique_lock are provided so that
// we can annotate them with thread safety attributes and use the
// -Wthread-safety warning with clang. The standard library types cannot be
// used directly because they do not provide the required annotations.
class CAPABILITY("mutex") Mutex {

그냥 추가하자

class BankAccount {
public:
    Mutex mu;

    int balance GUARDED_BY(mu);

    void depositImpl(int amount) {
        balance -= amount;
    }

    void withdrawImpl(int amount) REQUIRES(mu) {
      balance -= amount;       // OK. Caller must have locked mu.
    }
};

int main() {
    BankAccount account;
    account.depositImpl(10);

    account.mu.lock();
    account.withdrawImpl(100);

    return 0;
}

Lock 풀지 않았을 때 경고가 나오고,

newpolaris@Donghyuns-MacBook-Pro test2 % clang++ -Wthread-safety main.cpp --std=c++11 
main.cpp:27:9: warning: writing variable 'balance' requires holding mutex 'mu' exclusively [-Wthread-safety-analysis]
        balance -= amount;
        ^
main.cpp:44:1: warning: mutex 'account.mu' is still held at the end of function [-Wthread-safety-analysis]
}
^
main.cpp:39:16: note: mutex acquired here
    account.mu.lock();
               ^
2 warnings generated.

그걸, Google benchmark의 Berrier에 적용해보면

class Barrier {
 public:
  Barrier(int num_threads) : running_threads_(num_threads) {}

  // Called by each thread
  bool wait() EXCLUDES(lock_) {
    bool last_thread = false;
    {
      MutexLock ml(lock_);
      last_thread = createBarrier(ml);
    }
    if (last_thread) phase_condition_.notify_all();
    return last_thread;
  }

  void removeThread() EXCLUDES(lock_) {
    MutexLock ml(lock_);
    --running_threads_;
    if (entered_ != 0) phase_condition_.notify_all();
  }

 private:
  Mutex lock_;
  Condition phase_condition_;
  int running_threads_;

  // State for barrier management
  int phase_number_ GUARDED_BY(lock_) = 0;
  int entered_ GUARDED_BY(lock_) = 0;  // Number of threads that have entered this barrier

  // Enter the barrier and wait until all other threads have also
  // entered the barrier.  Returns iff this is the last thread to
  // enter the barrier.
  bool createBarrier(MutexLock& ml) REQUIRES(lock_) {
    entered_++;
    if (entered_ < running_threads_) {
      // Wait for all threads to enter
      int phase_number_cp = phase_number_;
      auto cb = [this, phase_number_cp]() REQUIRES(lock_) {
        return this->phase_number_ > phase_number_cp ||
               entered_ == running_threads_;  // A thread has aborted in error
      };
      phase_condition_.wait(ml.native_handle(), cb);
      if (phase_number_ > phase_number_cp) return false;
      // else (running_threads_ == entered_) and we are the last thread.
    }
    // Last thread has reached the barrier
    phase_number_++;
    entered_ = 0;
    return true;
  }
};

std::condition_variable 에 REQUIRES를 붙이는 건

https://stackoverflow.com/questions/40468897/clang-thread-safety-with-stdcondition-variable

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크