在多進程共享的應用程序中,通過「鎖」來對同一個計算資源進行協同是非常常見的做法,無論在單機或多機的系統、資料庫、文件系統中,都需要依賴「鎖」機制來避免並發訪問導致的不確定結果,今天我們就來講講文件系統中的「鎖」。
首先,文件鎖也是一種互斥機制,可確保多個進程以安全的方式讀取/寫入同一個文件。之所以要對這些多進程業務進行控制,就是因為這些進程的調度是不可預期的,這種時序上的不可預期會對同一個文件資源產生競爭性訪問,從而帶來預期外的結果。
我們可以看一個例子,以便更好地理解這個問題。
假設我們有一個 account.dat 文件,用於存儲帳戶余額,其初始值為「200」。並發系統有兩個進程來更新這個文件上的余額值:
顯然,在順序執行完這兩個進程後,我們期望文件具有以下值:200-20 + 80 = 260。
但是,如果進程的執行不是按預期的順序直徑,在以下這種情況下,可能會出現不一樣的結果:
結果,account.dat 文件中保存的余額就是 280 而不是預期值 260。
Linux 中的文件鎖
像前面提到的,文件鎖是一種在多個進程之間限制文件並發訪問的機制。它僅允許一個進程在特定時間內訪問文件,從而避免更新問題。
我們都知道 rm -rf / 在 Linux 中是非常危險的命令。如果我們以 root 用戶身份執行該命令,它甚至可以刪除正在運行的系統中的所有文件。這是因為 Linux 通常不會自動給打開的文件加鎖,所以即使是正在運行的文件,仍然有可能被 rm 命令刪除。Linux 支持兩種文件鎖:協同鎖(Advisory lock)和強制鎖(Mandatory lock)。
協同鎖(Advisory lock)
協同鎖定不是強制性鎖方案,僅當參與的進程通過顯式獲取鎖進行協作時,它才有效。否則,如果某個進程根本不知道鎖,則這個協同鎖會被忽略掉(意味著各個進程間必須協商並遵守這個協同鎖的機制,才能發揮鎖的作用)。
下面這個例子可以幫助我們更容易地理解協同鎖機制。讓我們先回顧一下我們之前提到的賬戶文件的例子。
首先,我們假設文件 account.dat 仍包含初始值 「200」。
進程 A 獲取 account.dat 文件的排他鎖,然後打開並讀取該文件以獲取當前值:200。
我們必須了解,協同鎖不是由操作系統或文件系統設置的。因此,即使進程 A 鎖定了文件,進程 B 仍然可以通過系統調用自由讀取、寫入或刪除文件。
如果進程 B 不嘗試在獲取鎖的情況下,就執行文件操作,則可以說進程 B 與進程 A 沒有使用協同鎖機制進行合作,仍然會帶來不可預期的結果。
現在,讓我們看一下鎖如何在協作流程中發揮作用:
強制鎖(Mandatory Lock)
與協作鎖不同,強制鎖不需要參與進程之間的任何合作。一旦在文件上激活了強制鎖,操作系統便會阻止其他進程讀取或寫入文件。
要在 Linux 中啟用強制性文件鎖定,必須滿足兩個要求:
使用強制鎖之後,這個鎖會在操作系統級別進行管理和控制。