在 C 11 中,我創建了 100 個執行緒,每個執行緒呼叫 Test::PushFunc,添加本地靜態變數index,插入到本地集變數localMap。
理論上,索引存盤在初始化資料段記憶體中,并在程式運行時由每個執行緒添加。以下線路
assert(it == localMap.end());
是合理的,因為要插入localMap的索引永遠不會重復。
但在實踐中,程式是在assert中隨機coredump的。你能告訴我為什么嗎?謝謝。
#include <set>
#include <iostream>
#include <thread>
class Test {
public:
std::set<std::string> localMap;
void PushFunc()
{
static uint64_t index = 0;
while (true) {
std::cout << "index : " << index << "\n";
index;
const auto& s = std::to_string(index);
const auto& it = localMap.find(s);
assert(it == localMap.end()); //! coredump here
localMap.insert(s);
if (index > 20000000) {
break;
}
}
}
};
int main ()
{
std::vector<std::thread> processThreads;
for (int i = 0; i < 100; i) {
processThreads.emplace_back(
std::thread([]()
{
Test t;
t.PushFunc();
}
));
}
for(auto& thread : processThreads){
thread.join();
}
}
uj5u.com熱心網友回復:
但在實踐中,程式是在assert中隨機coredump的。你能告訴我為什么嗎?
因為您有資料競爭——多個執行緒試圖在沒有任何同步的情況下讀取和寫入同一個變數。
該index是一個全域變數。您需要使用互斥鎖來保護對它的訪問。
日期:
但是localMap 不是全域變數,資料競爭無法解釋一個索引重復兩次。
- 具有資料競爭(未定義行為)的程式可以產生任何結果。
- 是的,它可以。
考慮以下指令交錯(時間向下):
- T1 加載
index到暫存器中(比如說5)。 - T2 負載
index(5再次) - T1
index增加到6,存盤"6"到它的映射中 - T1 加載
6、index增加到7、存盤"7"到它的映射中 - T2 將索引“增加”到
6,存盤"6"到它自己的映射中 - T1 加載
6,將其增加到7,嘗試將"7"其存盤到其映射中 ==> 斷言失敗!
問題是這index 不是原子操作,并且(沒有互斥鎖)其他執行緒可能會干擾它。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/399897.html
上一篇:我想在python中鎖定異步方法的一部分,基本上它應該是一個(基于名稱的鎖),其中名稱作為引數傳遞給方法
下一篇:執行緒池執行在C中的任意點停止
