[英]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之前)並在新線程上銷毀(顯然)。
這是安全的,因為新線程在存在之前不能與主線程競爭。
因此,這是一個線程清理程序錯誤。
它無法檢查上一次寫入時是否存在線程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.