深入理解linux互斥鎖(mutex)
鎖機制,可以說是linux整個系統的精髓所在,linux核心都是圍繞著同步在運轉。在多程序和多執行緒程式設計中,鎖起著極其重要的作用。我這裡說的是互斥鎖,其實是泛指linux中所有的鎖機制。我在這裡不講如果建立鎖,關於鎖的建立,網上程式碼很多,我在這裡就不多說了。我要談一談一個讓所有剛剛接觸鎖機制的程式設計師都很困惑的問題:如何使用以及鎖機制在程式中是如何運作的。
為什麼要使用鎖
這個就比較簡單,linux裡面,鎖的種類很多,包括互斥鎖,檔案鎖,讀寫鎖······其實訊號量說白了也是一種鎖。使用鎖的目的是達到同步的作用,使共享資源在同一時間內,只有能有一個程序或者執行緒對他進行操作。
linux是如何通過鎖來實現對資料的保護和維護的
這個問題是我要將的重點。很多剛剛接觸鎖機制的程式設計師,都會犯這種錯誤。比如,此時有2個執行緒,分別是執行緒A,執行緒B。A和B共享了資源M。為了同步A和B,使得同一時刻,同意時刻,只有一個執行緒對M操作。於是,很自然的會在A中對M資源先lock,等到A對M操作完畢之後,然後做一個操作unlock。B中則因為A加了鎖,B就直接操作M。這個時候,你會發現,B同樣可以操作到M。這個是為什麼呢?
我們利索當然的把檢測鎖的任務交給了作業系統,交給了核心。可以翻看APUE上對於所的講解,其中一部分是這麼寫的:
This mutual-exclusion mechanism works only if we design our threads to follow the same data-access rules. The operating system doesn't serialize access to data for us. If we allow one thread to access a shared resource without first acquiring a lock, then inconsistencies can occur even though the rest of our threads do acquire the lock before attempting to access the shared resource.
這裡This mutual-exclusion mechanism指的就是鎖機制。說的很清楚,只有程式設計師設計執行緒的時候,都遵循同一種資料訪問規則,鎖機制才會起作用。作業系統不會為我們序列化資料訪問,也就是說,作業系統不會為我們擬定任何資料訪問順序,到底是A在先還是B在先,作業系統不會為我們規定。如果我們允許一個執行緒在沒有多的鎖(lock)之前,就對共享資料進行訪問操作,那麼,即使我們其他的執行緒都在訪問之前試圖去先鎖住資源(獲取鎖),同樣會導致資料訪問不一致,即多個執行緒同時在操作共享資源。
從上面文字可以看出,作業系統不會為我們去檢查,此時是不是有執行緒已經把資源鎖住了。為了使鎖能夠正常工作,為了保護共享資源,我們只有在設計執行緒的時候,所有執行緒都用同一種方法去訪問共享資料,也就是訪問資料之前,務必先獲取鎖,然後再操作,操作完之後要解鎖(unlock)。作業系統提供鎖機制,就是提供了一種所有程式設計師都必須遵循的規範。而不是說我們鎖住資源,其他執行緒訪問共享資源的時候,讓作業系統去為我們檢查資料是否有其他的執行緒在操作。