W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
多年使用鎖的經驗 -- 早于 Linux 的經驗 -- 已經表明加鎖可能是非常難于正確的. 管理并發(fā)是一個固有的技巧性的事情, 有很多出錯的方式. 在這一節(jié), 我們快速看一下可能出錯的東西.
如同上面已經說過的, 一個正確的加鎖機制需要清晰和明確的規(guī)則. 當你創(chuàng)建一個可以被并發(fā)存取的資源時, 你應當定義哪個鎖將控制存取. 加鎖應當真正在開始處進行; 事后更改會是難的事情. 開始時花費的時間常常在調試時獲得回報.
當你編寫你的代碼, 你會毫無疑問遇到幾個函數(shù)需要存取通過一個特定鎖保護的結構. 在此, 你必須小心: 如果一個函數(shù)需要一個鎖并且接著調用另一個函數(shù)也試圖請求這個鎖, 你的代碼死鎖. 不論旗標還是自旋鎖都不允許一個持鎖者第 2 次請求鎖; 如果你試圖這樣做, 事情就簡單地完了.
為使的加鎖正確工作, 你不得不編寫一些函數(shù), 假定它們的調用者已經獲取了相關的鎖. 常常地, 只有你的內部的, 靜態(tài)函數(shù)能夠這樣編寫; 從外部調用的函數(shù)必須明確處理加鎖. 當你編寫內部函數(shù)對加鎖做了假設, 方便自己(和其他使用你的代碼的人)并且明確記錄這些假設. 在幾個月后可能很難回來并記起是否你需要持有一個鎖來調用一個特殊函數(shù).
在 sucll 的例子里, 采用的設計決定是要求所有的函數(shù)直接從系統(tǒng)調用里調用, 來請求應用到被存取的設備結構上的旗標. 所有的內部函數(shù), 那些只是從其他 scull 函數(shù)里調用的, 可以因此假設旗標已經正確獲得.
在有大量鎖的系統(tǒng)中(并且內核在成為這樣一個系統(tǒng)), 一次需要持有多于一個鎖, 對代碼是不尋常的. 如果某類計算必須使用 2 個不同的資源進行, 每個有它自己的鎖, 常常沒有選擇只能獲取 2 個鎖.
獲得多個鎖可能是危險的, 然而. 如果你有 2 個鎖, 稱為 Lock1 和 Lock2, 代碼需要同時都獲取, 你有一個潛在的死鎖. 僅僅想象一個線程鎖住 Lock1 而另一個同時獲得 Lock2. 接著每個線程試圖得到它沒有的那個. 2 個線程都會死鎖.
這個問題的解決方法常常是簡單的: 當多個鎖必須獲得時, 它們應當一直以同樣順序獲得. 只要遵照這個慣例, 象上面描述的簡單死鎖能夠避免. 然而, 遵照加鎖順序規(guī)則是做比說難. 非常少見這樣的規(guī)則真正在任何地方被寫下. 常常你能做的最好的是看看別的代碼如何做的.
一些經驗規(guī)則能幫上忙. 如果你必須獲得一個對你的代碼來說的本地鎖(假如, 一個設備鎖), 以及一個屬于內核更中心部分的鎖, 先獲取你的. 如果你有一個旗標和自旋鎖的組合, 你必須, 當然, 先獲得旗標; 調用 down (可能睡眠) 在持有一個自旋鎖時是一個嚴重的錯誤. 但是最重要的, 盡力避免需要多于一個鎖的情況.
第一個支持多處理器系統(tǒng)的 Linux 內核是 2.0; 它只含有一個自旋鎖. 這個大內核鎖將整個內核變?yōu)橐粋€大的臨界區(qū); 在任何時候只有一個 CPU 能夠執(zhí)行內核代碼. 這個鎖足夠好地解決了并發(fā)問題以允許內核開發(fā)者從事所有其他的開發(fā) SMP 所包含的問題. 但是它不是擴充地很好. 甚至一個 2 個處理器的系統(tǒng)可能花費可觀數(shù)量的時間只是等待這個大內核鎖. 一個 4 個處理器的系統(tǒng)的性能甚至不接近 4 個獨立的機器的性能.
因此, 后續(xù)的內核發(fā)布已經包含了更細粒度的加鎖. 在 2.2 中, 一個自旋鎖控制對塊 I/O 子系統(tǒng)的存取; 另一個為網絡而工作, 等等. 一個現(xiàn)代的內核能包含幾千個鎖, 每個保護一個小的資源. 這種細粒度的加鎖可能對伸縮性是好的; 它允許每個處理器在它自己特定的任務上工作而不必競爭其他處理器使用的鎖. 很少人忘記大內核鎖.[19]
但是, 細粒度加鎖帶有開銷. 在有幾千個鎖的內核中, 很難知道你需要那個鎖 -- 以及你應當以什么順序獲取它們 -- 來進行一個特定的操作. 記住加鎖錯誤可能非常難發(fā)現(xiàn); 更多的鎖提供了更多的機會使真正有害的加鎖 bug 鉆進內核中. 細粒度加鎖能帶來一定水平的復雜性, 長期來, 對內核的可維護性有一個大的, 不利的效果.
在一個設備驅動中加鎖常常是相對直接的; 你可以用一個鎖來涵蓋你做的所有東西, 或者你可以給你管理的每個設備創(chuàng)建一個鎖. 作為一個通用的規(guī)則, 你應當從相對粗的加鎖開始, 除非你有確實的理由相信競爭可能是一個問題. 忍住慫恿去過早地優(yōu)化; 真實地性能約束常常表現(xiàn)在想不到的地方.
如果你確實懷疑鎖競爭在損壞性能, 你可能發(fā)現(xiàn) lockmeter 工具有用. 這個補丁(從 http://oss.sgi.com/projects/lockmeter/ 可得到) 裝備內核來測量在鎖等待花費的時間. 通過看這個報告, 你能夠很快知道是否鎖競爭真的是問題.
[19] 這個鎖仍然存在于 2.6, 幾個它現(xiàn)在覆蓋內核非常小的部分. 如果你偶然發(fā)現(xiàn)一個 lock_kernel 調用, 你已找到了這個大內核鎖. 但是, 想都不要想在任何新代碼中使用它.
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: