一個讀取器執行緒和多個寫入器執行緒同時訪問 shared_ptr 物件并且運行良好,代碼如下(但是,如果我將寫入行代碼從“=”修改為“重置”,它將在讀取時進行核心轉儲):
shared_ptr.reset 表示核心轉儲,“operator =”表示運行良好?(我嘗試了 100 多次)
bool start = false;
std::mutex mtx;
std::condition_variable cond;
std::shared_ptr<std::string> string_ptr(new std::string("hello"));
int main() {
auto read = []() {
{
std::cout << "readddd" << std::endl;
std::unique_lock<std::mutex> lck(mtx);
while (!start) {
cond.wait(lck);
}
}
for (int i = 0; i < 100000; i) {
std::cout << *string_ptr.get() << std::endl;
}
};
auto write = []() {
{
std::unique_lock<std::mutex> lck(mtx);
while (!start) {
cond.wait(lck);
}
}
for (int i = 0; i < 100000; i) {
string_ptr = std::make_shared<std::string>(std::to_string(i));
// string_ptr.reset(new std::string(std::to_string(i))); // will coredump
}
};
std::thread w(write);
std::thread rthreads[20];
for (int i = 0; i < 20; i) {
rthreads[i] = std::thread(read);
}
{
std::unique_lock<std::mutex> lck(mtx);
start = true;
cond.notify_all();
}
w.join();
for (auto& t : rthreads) {
t.join();
}
return 0;
}
coredumpe 堆疊將是:
#0 0x00007fee5fca3113 在 std::basic_ostream<char, std::char_traits >& std::operator<< <char, std::char_traits, std::allocator >(std::basic_ostream<char, std::char_traits >& , std::basic_string<char, std::char_traits, std::allocator > const&) () from /lib64/libstdc .so.6 #1 0x00000000004039f0 in <lambda()>::operator()(void) const ( __closure=0xa54f98) 在 test_cast.cpp:395
行“std::cout << *string_ptr.get() << std::endl;”
uj5u.com熱心網友回復:
兩個版本都存在競爭條件。std::shared_ptr不是神奇的執行緒安全的。如果你想在執行緒之間共享它,你必須用互斥鎖來保護它。只是您嘗試了幾次并不能證明:這可能是因為它不太可能導致錯誤,甚至在您的編譯器/作業系統/CPU 組合上不可能發生錯誤,但這并不能保證。
如果您想更頻繁地看到它中斷,請在代碼中插入執行緒背景關系的開關。最簡單的方法是休眠一段時間,此時作業系統會調度一個不同的執行緒:
for (int i = 0; i < 100000; i) {
std::string* tmp = string_ptr.get();
std::this_thread::yield();
std::cout << *tmp << std::endl;
}
請注意,此代碼強制執行背景關系切換,但當超過執行緒的時間片時,相同的切換可能會在同一點自發地發生。
至于為什么一個比另一個更容易失敗,請逐步執行由shared_ptr的賦值運算子和reset()成員函式執行的指令。他們的實作可能有更大或更小的臨界區,控制錯誤出現的頻率。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/362898.html
