第二章 線程管理
數據保護
從樂觀的角度上看,還是有方法可循的:切勿將受保護數據的指針或引用傳遞到互斥鎖作用域之外,無論是函數返回值,還是存儲在外部可見內存,亦或是以參數的形式傳遞到用戶提供的函數中去
盡管鏈表的個別操作是安全的,但不意味著你就能走出困境;即使在一個很簡單的接口中,依舊可能遇到條件競爭。例如,構建一個類似于 std::stack 結構的棧(清單3.3),除了構造函數和swap()以外,需要對 std::stack 提供五個操作:push()一個新元素進棧,pop()一個元素出棧,top()查看棧頂元素,empty()判斷棧是否是空棧,size()了解棧中有多少個元素。即使修改了top(),使其返回一個拷貝而非引用(即遵循了3.2.2節的準則),對內部數據使用一個互斥量進行保護,不過這個接口仍存在條件競爭。這個問題不僅存在于基于互斥量實現的接口中,在無鎖實現的接口中,條件競爭依舊會產生。這是接口的問題,與其實現方式無關。
檢查迷失指針
不過,檢查迷失指針或引用是很容易的,只要沒有成員函數通過返回值或者輸出參數的形式向其調用者返回指向受保護數據的指針或引用,數據就是安全的
不需要全局變量
雖然某些情況下,使用全局變量沒問題,但在大多數情況下,互斥量通常會與保護的數據放在同一個類中,而不是定義成全局變量。這是面向對象設計的準則:將其放在一個類中,就可讓他們聯系在一起,也可對類的功能進行封裝,并進行數據保護。在這種情況下,函數add_to_list和list_contains可以作為這個類的成員函數。互斥量和要保護的數據,在類中都需要定義為private成員,這會讓訪問數據的代碼變的清晰,并且容易看出在什么時候對互斥量上鎖。當所有成員函數都會在調用時對數據上鎖,結束時對數據解鎖,那么就保證了數據訪問時不變量不被破壞。