共享資料練習題 (Practice - Sharing Data)


Question 1 - 競爭條件與資料競爭 [recall]

「競爭條件」與 C++ 標準所定義的「資料競爭」有何區別?為什麼競爭條件造成的 bug 常在除錯模式下完全消失?


Question 2 - lock_guard 與引用外洩 [recall]

為什麼不建議直接呼叫 std::mutex 的 lock()/unlock(),而要用 std::lock_guard?即使每個成員函式都正確上鎖,哪種常見寫法仍會讓保護「形同虛設」?


Question 3 - stack 介面固有競爭 [recall]

一個內部用 mutex 保護的共享堆疊,使用者寫 if(!s.empty()){ int v = s.top(); s.pop(); }。指出這段程式碼中的兩個競爭條件,並說明為何「換成無鎖實作」也救不了。


Question 4 - std::lock 與 adopt_lock [recall]

std::lock(lhs.m, rhs.m); 之後緊接兩行 std::lock_guard<std::mutex> a(lhs.m, std::adopt_lock);,std::adopt_lock 的意義是什麼?若 std::lock 鎖第二個 mutex 時拋出例外,第一個 mutex 會怎樣?C++17 有何更簡潔的寫法?


Question 5 - DCLP、call_once 與 static 初始化 [recall]

雙重檢查鎖定 (DCLP) 為什麼聲名狼藉?C++ 標準庫對「昂貴資源只初始化一次」與「全域唯一實例」各提供什麼正解?


Question 6 - shared_mutex 讀寫鎖 [recall]

DNS 快取表讀多寫少,用哪種 mutex?讀者與寫者各用什麼鎖類型?C++11/14/17 各提供什麼?


Question 7 - 鎖層級違規診斷 [application]

系統定義 hierarchical_mutex 層級:high=10000、other=6000、low=5000。thread_b 先鎖 other_mutex(6000),再呼叫會鎖 high_level_mutex(10000) 的函式。會發生什麼事?為何 hierarchical_mutex 能直接放進 std::lock_guard?


Question 8 - unique_lock 與鎖粒度 [application]

get_and_process_data() 需要:取共享資料塊 → 呼叫耗時的 process()(不碰共享資料)→ 寫回結果。用 std::lock_guard 全程持鎖被抱怨太慢,如何用 std::unique_lock 改善?寫出關鍵程式碼。


Question 9 - threadsafe_stack 的 pop 設計 [analysis]

std::stack 把 top() 與 pop() 分開是為了解決什麼問題?threadsafe_stack 合併它們後,這個問題如何在「選項 1(傳入引用)+ 選項 3(回傳 shared_ptr)」的設計下被化解?分析各選項的代價。


Question 10 - recursive_mutex 是解藥還是壞味道 [analysis]

成員函式 A(已上鎖)呼叫也要上鎖的成員函式 B,對 std::mutex 重複上鎖是 UB。同事提議「換成 std::recursive_mutex 就能跑了」。分析這個方案的問題與更好的做法。