檔案鎖是一種檔案讀寫機制,在任何特定的時間只允許乙個程序訪問乙個檔案。利用這種機制能夠使讀寫單個檔案的過程變得更安全。這裡我們使用flock()函式。
flock函式說明:flock()會依引數operation所指定的方式對引數fd所指的檔案做各種鎖定或解除鎖定的動作。此函式只能鎖定整個檔案,無法鎖定檔案的某一區域。
標頭檔案 #include
引數 operation有下列四種情況:
lock_sh 建立共享鎖定。多個程序可同時對同乙個檔案作共享鎖定。
lock_ex 建立互斥鎖定。乙個檔案同時只有乙個互斥鎖定。
lock_un 解除檔案鎖定狀態。
lock_nb 無法建立鎖定時,此操作可不被阻斷,馬上返回程序。通常與lock_sh或lock_ex 做or(|)組合。
單一檔案無法同時建立共享鎖定和互斥鎖定,而當使用dup()或fork()時檔案描述詞不會繼承此種鎖定。
返回值 返回0表示成功,若有錯誤則返回-1,錯誤**存於errno。
flock只要在開啟檔案後,需要對檔案讀寫之前flock一下就可以了,用完之後再flock一下,前面加鎖,後面解鎖。
程序使用flock嘗試鎖檔案時,如果檔案已經被其他程序鎖住,程序會被阻塞直到鎖被釋放掉,或者在呼叫flock的時候,採用lock_nb引數,在嘗試鎖住該檔案的時候,發現已經被其他服務鎖住,會返回錯誤。
flock鎖的釋放非常具有特色,即可呼叫lock_un引數來釋放檔案鎖,也可以通過關閉fd的方式來釋放檔案鎖(flock的第乙個引數是fd),意味著flock會隨著程序的關閉而被自動釋放掉
當使用lock_ex 排他鎖時,同一時刻只能有乙個程序鎖定成功,其餘進行只能阻塞,這種行為與多執行緒讀寫鎖中的寫鎖類似。
//lock
if ((lock_fd = open(lock_path, o_creat|o_wronly, 0664)) < 0)
if (flock(lock_fd, lock_ex) < 0)
//unlock
close(lock_fd);
這三個函式的作用都是給檔案加鎖,那它們有什麼區別呢?
首先flock和fcntl是系統呼叫,而lockf是庫函式。lockf實際上是fcntl的封裝,所以lockf和fcntl的底層實現是一樣的,對檔案加鎖的效果也是一樣的。後面分析不同點時大多數情況是將fcntl和lockf放在一起的。
關於flock函式,首先要知道flock函式只能對整個檔案上鎖,而不能對檔案的某一部分上鎖,這是於fcntl/lockf的第乙個重要區別,後者可以對檔案的某個區域上鎖。
其次,flock只能產生勸告性鎖。我們知道,linux存在強制鎖(mandatory lock)和勸告鎖(advisory lock)。所謂強制鎖,比較好理解,就是你家大門上的那把鎖,最要命的是只有一把鑰匙,只有乙個程序可以操作。所謂勸告鎖,本質是一種協議,你訪問檔案前,先檢查鎖,這時候鎖才其作用,如果你不那麼kind,不管三七二十一,就要讀寫,那麼勸告鎖沒有任何的作用。而遵守協議,讀寫前先檢查鎖的那些程序,叫做合作程序。
再加上,flock可以有共享鎖和排它鎖,lockf只支援排它鎖,但是fcntl裡面引數flock可以有rdlck讀鎖。
再次,flock和fcntl/lockf的區別主要在fork和dup時候的區別,後面有講。
另外,flock不能再nfs檔案系統上使用,如果要在nfs使用檔案鎖,請使用fcntl。
l 函式原型
#include
int lockf(int fd, int cmd, off_t len);
fd為通過open返回的開啟檔案描述符。
cmd的取值為:
f_lock:給檔案互斥加鎖,若檔案以被加鎖,則會一直阻塞到鎖被釋放。
f_tlock:同f_lock,但若檔案已被加鎖,不會阻塞,而回返回錯誤。
f_ulock:解鎖。
f_test:測試檔案是否被上鎖,若檔案沒被上鎖則返回0,否則返回-1。
len:為從檔案當前位置的起始要鎖住的長度。
通過函式引數的功能,可以看出lockf只支援排他鎖,不支援共享鎖。
#include
#include
int fcntl(int fd, int cmd, ... /* arg */ );(用法:int ret = fcntl(fd, f_setlkw, &lock);)
其實的lock就是下面的資料結構:
struct flock 測試結果如下:
$./a.out
flock return ret : 0
lockf return ret: 0
可見flock的加鎖,並不影響lockf的加鎖。兩外我們可以通過/proc/locks檢視程序獲取鎖的狀態。
$ps aux | grep a.out | grep -v grep
123751 18849 0.0 0.0 11904 440 pts/5 s+ 01:09 0:00 ./a.out
$sudo cat /proc/locks | grep 18849
1: posix advisory write 18849 08:02:852674 0 eof
2: flock advisory write 18849 08:02:852674 0 eof
我們可以看到/proc/locks下面有鎖的資訊:我現在分別敘述下含義:
1) posix flock 這個比較明確,就是哪個型別的鎖。flock系統呼叫產生的是flock,fcntl呼叫f_setlk,f_setlkw或者lockf產生的是posix型別,可見兩種呼叫產生的鎖的型別是不同的;
2) advisory表明是勸告鎖;
3) write顧名思義,是寫鎖,還有讀鎖;
4) 18849是持有鎖的程序id。當然對於flock這種型別的鎖,會出現程序已經退出的狀況。
5) 08:02:852674表示的對應磁碟檔案的所在裝置的主裝置號,次裝置號,還有檔案對應的inode number。
6) 0表示的是所的其實位置
7) eof表示的是結束位置。 這兩個欄位對fcntl型別比較有用,對flock來是總是0 和eof。
fcntl支援強制性鎖:對乙個特定檔案開啟其設定組id位(s_isgid),並關閉其組執行位(s_ixgrp),則對該檔案開啟了強制性鎖機制。再linux中如果要使用強制性鎖,則要在檔案系統mount時,使用-omand開啟該機制。
#include #include int main(int argc, char **ar**)
static struct flock lock;
lock.l_type = f_wrlck;
lock.l_start = 0;
lock.l_whence = seek_set;
lock.l_len = 0;
lock.l_pid = getpid();
int ret = fcntl(fd, f_setlkw, &lock);
printf("return value of fcntl:%d\n",ret);
if(ret==0)
}}}
使用mount命令帶「mand」引數來重新掛載根檔案系統,如下所示。這將在檔案系統級別使能強制鎖功能。注意:你必須切換到root使用者才能執行下面的命令。# mount -oremount,mand /
在可執行的(file_lock所在的)目錄中建立兩個名為「advisory.txt」和「mandatory.txt」的檔案。對於「mandatory.txt」使能set-group-id,同時不使能group-execute-bit,如下所示:
# touch advisory.txt測試協同鎖:# touch mandatory.txt
# chmod g+s,g-x mandatory.txt
執行示例程式,以「advisory.txt」作為引數。
# ./file_lock advisory.txt
此程式將等待使用者的輸入。從另乙個終端或控制台,嘗試輸入以下命令列(不檢查鎖,直接輸入):
# ls >>advisory.txt
在上面的例子中,ls命令會將其輸出寫入到advisory.txt檔案中。即使我們獲得了乙個寫入鎖,仍然會有一些程序(非合作)能夠往檔案裡寫入資料。這就是所謂的「協同」鎖。
測試強制鎖:
再次執行示例程式,以「mandatory.txt」作為引數。
# ./file_lock mandatory.txt
從另乙個終端或控制台,嘗試輸入以下命令列:
# ls >>mandatory.txt
在上面的例子中,ls命令在將其輸出寫入到mandatory.txt檔案之前,會等待檔案鎖被刪除。雖然它仍然是乙個非合作程序,但強制鎖起了作用。
Linux flock檔案鎖詳解
摘要1 摘要2 摘要3 用flock命令解決linux計畫任務重複執行 在做計畫任務的時候,可能由於某些問題,任務沒有執行完成,導致任務重複的執行,解決這個問題,只需要乙個flock命令就可以了。1.建立s 件 vim test.sh bin bash echo hello world sleep ...
flock 函式 檔案鎖
檔案鎖是一種檔案讀寫機制,在任何特定的時間只允許乙個程序訪問乙個檔案。利用這種機制能夠使讀寫單個檔案的過程變得更安全。這裡我們使用flock 函式。flock函式說明 flock 會依引數operation所指定的方式對引數fd所指的檔案做各種鎖定或解除鎖定的動作。此函式只能鎖定整個檔案,無法鎖定檔...
php中檔案鎖函式flock函式用法簡介
php中檔案鎖函式flock函式用法簡介 語法 bool flock int handle int operation int wouldblock flock 操作的 handle 必須是乙個已經開啟的檔案指標。operation 可以是以下值之一 1.要取得共享鎖定 讀取程式 將 operati...