對文件加鎖是原子性的,可以用于進程間文件操作的同步。在linux下,有三個函數可以對文件進程加鎖,分別是fcntl、flock、lockf。這里只說fcntl,它的用法也是最復雜的。
fcntl是file control的縮寫。在linux下大部分設備都是文件,所以fcntl的功能也比較多,包括:
•Duplicating a file descriptor(復制文件描述符)
•File descriptor flags(操作close-on-exec標志)
•File status flags(操作文件O_RDONLY , O_WRONLY , O_RDWR , O_APPEND , O_NONBLOCK , O_SYNC和O_ASYNC標識)
•Advisory locking(建議性鎖)
•Mandatory locking(強制性鎖)
•Managing signals(管理信號)
•Leases(租借鎖)
•File and directory change notification (dnotify)(文件和目錄更改消息)
•Changing the capacity of a pipe(改變管道大小)
這里只說一下Advisory locking和Mandatory locking。建議性鎖是指給文件上鎖后,只在文件上設置了一個鎖的標識。其他進程在對這個文件進程操作時,可以檢測到鎖的存在,但這個鎖并不能阻止它對這個文件進行操作。這就好比紅綠燈,當亮紅燈時,告訴你不要過馬路,但如果你一定要過,也攔不住你。強制性鎖則是當給文件上鎖后,當其他進程要對這個文件進程不兼容的操作(如上了讀鎖,另一個進程要寫),則系統內核將阻塞后來的進程直到第一個進程將鎖解開。在該功能下,fcntl的函數原型為:
Advisory locking共有三個操作,分別是F_GETLK、F_SETLK、F_SETLKW。其中F_GETLK用來測試鎖,注意是測試而不是獲取鎖;F_SETLK用來加鎖、解鎖;F_SETLKW功能同F_SETLK,只是操作變成阻塞式的。而fcntl可以用過l_whence、l_start、l_len來控制文件上鎖的區間。下面分別是上鎖、測試鎖的代碼。
在上面的代碼中,"_lock.l_type = F_RDLCK;"表示給文件上讀共享鎖,"_lock.l_whence = SEEK_SET;"表示從文件開頭開始加鎖,"_lock.l_start = 0;"表示偏移l_whence多少字節開始加鎖,"_lock.l_len = 0;"表示加鎖的字節數,即長度(Specifying 0 for l_len has the special meaning: lock all bytes starting at the location specified by l_whence and l_start through to the end of file, no matter how large the file grows.)。
在上面的代碼中,分別編譯為slock、glock。先運行slock再運行glock:
slock先給文件上寫鎖,然后glock測試讀共享鎖是否能加上,測試結果是已存在一個寫鎖(F_WRLCK,debian下定義為1)。這里需要注意的是F_GETLK是測試鎖是否能加上,如果可以,則struct flock中的l_type為F_UNLCK;如果不行,則l_type為文件當前鎖的類型,而l_pid為上鎖的進程pid。故如果slock上的鎖是F_RDLCK,glock測試的鎖也是F_RDLCK,這兩個鎖是兼容的,返回的l_type類型為F_UNLCK。即你不能通過F_GETLK來判斷文件是否上鎖,只能測試某個鎖是否能加上。
上面的是建議性鎖,如果要實現強制性鎖,則:
這是說,要實現強制性鎖則須將文件所在的文件系統用"-o mand"參數來掛載,并且使用chmod函數將文件用戶組的x權限去掉。然后用上面同樣的代碼就可以了。我第一次見這么奇特的函數,實現一個功能并不是通過本身的參數控制,而是系統設置.....幸好我也不用強制性鎖。
以上是fcntl加文件鎖的簡單例子。需要注意的是不同系統的實現并不一樣,宏定義也不一樣。如:
http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/fcntl.h
/* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */
#define F_RDLCK 1 /* shared or read lock */
#define F_UNLCK 2 /* unlock */
#define F_WRLCK 3 /* exclusive or write lock */
而在debian中,/usr/include/bits/fcntl.h
/* For posix fcntl() and `l_type' field of a `struct flock' for lockf(). */
#define F_RDLCK 0 /* Read lock. */
#define F_WRLCK 1 /* Write lock. */
#define F_UNLCK 2 /* Remove lock. */
新聞熱點
疑難解答