關於LINUX的文件鎖的一些心得

在之前的一個項目中用到了文件鎖,從網上粗略的查了下資料就匆匆忙忙的用上了,雖然當時也有一些疑惑,但是由於項目進度比較緊,也沒有多想。現在,終於有點時間可以稍微靜下心來看看這個文件鎖到底是怎麼一回事了。

從內核實現的角度來看,每當創建一把文件鎖的時候,系統就會實例化一個struct file_lock對象,這個file_lock對象會記錄鎖的相關信息:如鎖的類型(共享鎖,獨佔鎖)、擁有這把鎖的進程號、鎖的標識(租賃鎖,阻塞鎖,POSIX鎖,FLOCK鎖),等等。最後把這個file_lock對象插入到被鎖文件的inode.i_flock鏈表中,就完成了對該文件的加鎖功能。要是其它進程想要對同一個文件加鎖,那麼它在將file_lock對象插入到inode.i_flock之前,會遍歷該鏈表,如果沒有發現衝突的鎖,就將其插入到鏈表尾,表示加鎖成功,否則失敗。
至於爲什麼要將inode與file_lock以鏈表的形式關聯起來,主要是考慮到用戶有時可以對同一個文件加多個文件鎖。例如:我們可以對同一個文件加多個共享鎖;或者我們可以同時對文件加POSIX鎖和FLOCK鎖,這兩種鎖分別對應flock()和fcntl()兩種系統調用函數;再或者可以通過多次調用fcntl()對同一個文件中的多個內容塊加上POSIX記錄鎖。

下面講下POSIX鎖和FLOCK鎖的一些區別:


1. POSIX鎖和FLOCK鎖分別是通過fcntl()和flock()系統調用完成的。雖然實現的原理上都差不多,都是生成一個file_lock對象並插入inode文件鎖鏈表,但是POSIX鎖是支持針對某一段文件內容進行加鎖的,而FLOCK鎖不支持。

2. POSIX鎖可以重複加鎖,即同一個進程,可以對同一個文件多次加同樣一把鎖。例如:第一次我對A文件的一個0~10的內容塊加了一把獨佔鎖,那麼第二次同一個進程中我一樣可以對這個A文件的0~10的內容塊再加一把獨佔鎖,這個有點像是遞歸加鎖,但是我解鎖時只需要解一次。FLOCK鎖則不同,如果你第一次對A文件加了一把獨佔鎖,那麼在同一個進程中你就不能對A文件再加一把鎖了。這個區別其實只不過是在加鎖的時候,遍歷inode.i_flock鏈表時,發現存在PID相同的鎖時,系統對於POSIX鎖和FLOCK鎖的具體處理手段不一樣罷了。

3. 通過第2點,我們可以想象一下,POSIX鎖和FLOCK鎖在多線程環境下的不同。我們知道從Linux內核的視角來看,它是不區分所謂的進程和線程的,都不過是CPU調度隊列中的一個個task_struct實例而已,所以不會對線程的場景進行專門的處理,也正以爲如此,平時我們用的NPTL線程庫也都是在用戶態環境中模擬出來的,Linux內核並不直接支持。回到剛剛的話題,因爲內核它在加鎖的時候是看PID的,所以在內核看來多線程的加鎖只不過是同一個進程(因爲每個線程的PID都是一樣的)在對同一個文件加多把鎖。這樣,多線程環境下的加鎖行爲就表現爲:同一個進程中的多個線程可以對同一個文件加多次POSIX獨佔或共享鎖,但是不可以對同一個文件加多次FLOCK獨佔鎖(不過共享鎖是可以加多次的)。

4. 在一個項目中使用了GPFS共享文件系統,我們在開發過程中發現,對於FLOCK鎖只支持本地,而POSIX鎖則可以支持跨主機加鎖。例如:我們有兩臺獨立的機器A和B,在A機器上有某個進程對文件f加POSIX獨佔鎖,然後在B機器上當有某個進程想對f加POSIX獨佔鎖時,就會失敗。可是當我們使用FLOCK鎖時,就發現兩臺機器對同一個文件加FLOCK鎖是互不影響的,即A和B機器都可以對f加獨佔鎖。針對這種情況,IBM工程師在郵件中給出的解釋如下:



關於文件鎖的其他一些細節性的東西,可以參考這篇文章:http://www.ibm.com/developerworks/cn/linux/l-cn-filelock/
對於一些更加底層的細節問題,如:加鎖過程是隻在VFS層操作還是涉及到具體的物理文件系統、GPFS上的POSIX文件鎖如何做到跨機器有效,等等問題,可能就要參考源代碼了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章