簡體   English   中英

在多線程環境中使用std :: string時,Clang的線程清理程序警告

[英]Clang's thread sanitizer warning while using std::string in a multi-threaded environment

在使用clang的線程消毒劑時,我們注意到了數據競爭警告。 我們認為這是由於std :: string的copy-on-write技術不是線程安全的,但我們可能是錯的。 我們減少了對此代碼的警告:

void test3() {
  std::unique_ptr<std::thread> thread;

  {
    auto output = make_shared<string>();
    std::string str = "test";
    thread.reset(new std::thread([str, output]() { *output += str; }));
    // The str string now goes out of scope but due to COW
    // the captured string may not have the copy of the content yet.
  }

  thread->join();
}

在使用線程清理程序編譯時:

clang++ -stdlib=libc++ -std=c++11 -O0 -g -fsanitize=thread -lpthread -o test main.cpp

要么

clang++ -std=c++11 -O0 -g -fsanitize=thread -lpthread -o test main.cpp

並且當多次運行時,它最終會產生此警告:

WARNING: ThreadSanitizer: data race (pid=30829)
  Write of size 8 at 0x7d0c0000bef8 by thread T62:
    #0 operator delete(void*) <null>:0
    ...

  Previous write of size 1 at 0x7d0c0000befd by thread T5:
    #0 std::__1::char_traits<char>::assign(char&, char const&) string:639
    ...

這是線程消毒器的假陽性還是真正的數據競爭? 如果是后者,它可以在不更改代碼的情況下工作(例如通過將一些標志傳遞給編譯器),這是字符串實現中的已知錯誤(或其他內容)嗎?

更新: clang --version輸出:

Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)
Target: x86_64-pc-linux-gnu
Thread model: posix

更新:我用來重現此警告的cpp

[edit]下面的假設結果是錯誤的,請參閱評論中的鏈接。 T5,而不是T62是上面代碼中產生的線程。

理解線程ID是有用的,但我假設T5是主線程,T62是生成線程。 看起來副本是在主線程上(在新線程被spwaned之前)並在新線程上銷毀(顯然)。 這是安全的,因為新線程在存在之前不能與主線程競爭。

\n

因此,這是一個線程清理程序錯誤。 它無法檢查上一次寫入時是否存在線程T62。

這非常棘手。 我在下面的代碼中總結了邏輯:

In thread T62:
        Create string s (with reference count)
        Create output_1 pointing to s in the thread storage for T62 
        Create thread T5
        Create output_2 pointing to s in the thread storage for T5
    Sync point
    In thread T5:
        Append to s   ** MODIFY **
        Thread-safe decrement of reference count for s (not a sync point)
        End of output_2 lifetime
        Exit
    In thread T62:
        Thread-safe decrement of reference count for s (not a sync point)
        End of output_1 lifetime
        Deallocate s  ** MODIFY **
        Join
    Sync point
    In thread T62:
        Destroy T5

據我所知,該標准不保證調用shared_ptr刪除器的同步:

(20.8.2.2/4)為了確定是否存在數據爭用,成員函數應僅訪問和修改shared_ptr和weak_ptr對象本身,而不是它們所引用的對象。

我認為這意味着在調用shared_ptr的成員函數時實際發生在指向對象上的任何修改,例如刪除器可能進行的任何修改,都被認為超出了shared_ptr的范圍,因此它shared_ptr不負責確保他們不引入數據競爭。 例如,在T62嘗試銷毀它時,T62對字符串的修改可能對T62不可見。

然而,Herb Sutter在他的“Atomic <>武器”談話中表示,他認為這是一個錯誤,在shared_ptr析構函數中沒有獲取和釋放語義的引用計數的原子減少,但我不知道它是怎么回事違反了標准。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM