轉自 http://blog.csdn.net/yebanghua/article/details/7301904
第一節Unix支持的文件鎖技術介紹
Unix系統允許多個進程同時對一個文件進行讀寫,雖然每一個read或write調用本身是原子的,但內核在兩個讀寫操作之間並沒有加以同步,因此當一個進程多次調用read來讀文件時,其它進程有可能在兩次read之間改變該文件,造成文件數據的隨機性衝突。爲解決此類併發進程對共享文件的訪問控制問題,Unix系統設計了文件鎖技術。
1.1 讀鎖與寫鎖
Unix系統對文件加鎖有兩種粒度:文件鎖和記錄鎖,文件鎖用來鎖定整個文件,而記錄鎖可以鎖定文件的部分區域甚至一個字節,進程通過爲文件設置多個記錄鎖,可以實現文件中不同區域的數據的讀寫同步,因此記錄鎖最爲常見。記錄鎖根據訪問方式的不同,又分爲讀鎖和寫鎖。讀鎖允許多個進程同時進行讀操作,也稱共享鎖。文件加了讀鎖就不能再設置寫鎖,但仍允許其他進程在同一區域再設置讀鎖。寫鎖的主要目的是隔離文件使所寫內容不被其他進程的讀寫干擾,以保證數據的完整性。寫鎖一旦加上,只有上鎖的人可以操作,其他進程無論讀還是寫只有等待寫鎖釋放後才能執行,故寫鎖又稱互斥鎖,寫鎖與任何鎖都必須互斥使用。
|
是否滿足請求 |
|
當前加上的鎖 |
共享鎖(讀鎖) |
排他鎖(寫鎖) |
無 |
是 |
是 |
共享鎖(讀鎖) |
是 |
否 |
排他鎖(寫鎖) |
否 |
否 |
表 1. 鎖間的兼容關係
1.2 建議鎖和強制鎖
Unix文件鎖根據實現機制的不同,又可分爲建議鎖和強制鎖兩種類型。建議鎖由應用層實現,內核只爲用戶提供程序接口,並不參與鎖的控制和協調,也不對讀寫操作做內部檢查和強制保護,其工作原理類似於信號量機制,用戶首先定義並初始化特定的鎖,再根據進程間的的關係來調用相應的鎖操作,只有所有進程都嚴格遵循鎖的使用規則,纔能有效防止同步錯誤,否則,只要有一個例外,整個鎖的功能就會被破壞。
強制鎖則由內核強制實施,每當有進程調用read或write時,內核都要檢查讀寫操作是否與已加的鎖衝突,如果衝突,阻塞方式下該進程將被阻塞直到鎖被釋放,非阻塞方式下系統將立即以錯誤返回。顯然,使用強制鎖來控制對已鎖文件或文件區域的訪問,是更安全可靠的同步形式,適用於網絡連接、終端或串並行端口之類須獨佔使用的設備文件,因爲對用戶都可讀的文件加一把強制讀鎖,就能使其他人不能再寫該文件,從而保證了設備的獨佔使用。由於強制鎖運行在內核空間,處理機從用戶空間切換到內核空間,系統開銷大,影響性能,所以應用程序很少使用。建議鎖開銷小,可移植性好,符合POSIX標準的文件鎖實現,在數據庫系統中應用廣泛,特別是當多個進程交叉讀寫文件的不同部分時,建議鎖有更好的並行性和實時性。
文件存在鎖的類型 |
阻塞描述符,試圖 |
非阻塞描述符,試圖 |
||
read |
write |
read |
write |
|
讀鎖 |
允許 |
阻塞 |
允許 |
EAGAIN錯誤 |
寫鎖 |
阻塞 |
阻塞 |
EAGAIN錯誤 |
EAGAIN錯誤 |
表2強制性鎖對其他進程讀、寫的影響
系統 |
建議性鎖 |
強制性鎖 |
Linux2.4.22 |
支持 |
支持 |
Solaris 9 |
支持 |
支持 |
Mac OS X 10.3 |
支持 |
不支持 |
FreeBSD 5.2.1 |
支持 |
不支持 |
表3 不同系統的支持情況
第二節 文件鎖的總體實現和設置
2.1 內核相關的數據結構
Unix文件鎖是在共享索引節點共享文件的情況下設計的,因此與鎖機制相關的內核數據結構主要有虛擬索引節點(V-node)、系統打開文件表、進程打開文件表等數據表項。其中V-node中的索引節點(i-node)中含有一個指向鎖鏈表的首指針,該鎖鏈表主要由對文件所加的全部的鎖通過指針鉤鏈而成。只要進程爲文件或區域加鎖成功,內核就創建鎖結構file lock,並根據用戶設定的參數初始化後將其插入鎖鏈表flock中。flock是鎖存在的唯一標誌,也是內核感知、管理及控制文件鎖的主要依據,其結構和成員參見圖1中的struct flock。圖1描述了進程爲打開的文件設置文件鎖的內核相關表項及各數據結構之間的關聯,從中可以看出,鎖同時與進程和文件相關,當進程終止或文件退出時即使是意外退出,進程對文件所加的鎖將全部釋放。
圖1 文件鎖相關數據結構示意
2.2 鎖的使用
Unix提供了3個文件鎖相關的系統調用:flock、lockf和fcntl。其中fcntl功能強大,使用靈活,移植性好,既支持建議式記錄鎖也支持強制式記錄鎖,函數原型定義爲:int fcntl(int fd,int cmd,int arg),參數fd表示需要加鎖的文件的描述符;參數cmd指定要進行的鎖操作,如設置、解除及測試鎖等;參數arg是指向鎖結構flock的指針。
無論哪種類型的文件鎖,使用的流程是確定的:首先以匹配的方式打開文件,然後各進程調用上鎖操作同步對已鎖區域的讀寫,讀或寫完成時再調用解鎖操作,最後關閉文件。鎖操作代碼的編寫方法基本類似,首先形成適當的flock結構,然後調用fcntl完成實際的鎖操作。爲避免每次分配flock並填充各成員的重複工作,可以預先定義專門的函數來完成頻繁調用的上鎖和解鎖操作。下列代碼就是爲一個文件設置讀鎖的實例。
int set_read_lock(intfd, int cmd, int type, off_t start, int whence, off_t len)
{
struct flock lock;
lock.l_type=F_RDLCK;
lock.l_pid=getpid();
lock.l_whence=SEEK_SET;
lock.l_start=0;
lock.l_len=0;
return (fcntl(fd, F_SETLKW, &lock));
}
2.3 強制性鎖的設置
強制性鎖的設置需要兩個步驟:第一,對要加鎖的文件需要設置相關權限,打開set-group-ID位,關閉group-execute位。第二,讓linux支持強制性鎖,需要執行命令,掛載文件系統, mount /dev/sda1 /mnt –o mand。
# mount -o mand/dev/sdb7 /mnt
# mount | grep mnt
/dev/sdb7 on /mnt typeext3 (rw,mand)
# touch /mnt/testfile
# ls -l /mnt/testfile
-rw-r--r-- 1 root root 0 Jun 22 14:43 /mnt/testfile
# chmod g+s /mnt/testfile
# chmod g-x /mnt/testfile
# ls -l /mnt/testfile
-rw-r-Sr-- 1 root root 0 Jun 22 14:43 /mnt/testfile
附件中的測試程序(lock.c)可以測試是否支持強制性鎖。
2.4 設置強制性鎖注意問題
在設置強制性鎖注意的問題:幾乎所有的操作都需要root權限。
1. 首先,su到root權限下,輸入:mount 可以看到掛載的所有內容,如果所用磁盤存在其他掛載路徑,要讓mand成功,必須是:所用磁盤(sda1)被掛載的方式有mand存在。
比如存在: /dev/sda1 on /boot type ext3(rw)
/dev/sda1 on /opt/327/XXX typeext3(rw, mand)
則不成功。
需要: /dev/sda1 on /boot typeext3(rw, mand)
/dev/sda1 on /opt/327/XXX type ext3(rw,mand)
2.mount /dev/sda1 /opt/327/XXX/ -o mand,把sda1磁盤掛載到/opt/327/XXX/目錄下,此時,把新文件存在opt/327/XXX/下,實際是存在sda1磁盤中。
3. 此時/opt/327/XXX/的權限變成了root,只用root權限的用戶才能修改這個文件夾下的內容。
第三節 三種加鎖方法詳細介紹和linux內部實現
3.1 Posix lock加鎖的方法(fcntl):
3.1.1使用介紹:
fcntl() 函數的功能很多,可以改變已打開的文件的性質,本文中只是介紹其與獲取/設置文件鎖有關的功能。fcntl() 的函數原型如下所示:
int fcntl (int fd, int cmd, struct flock *lock); |
其中,參數 fd 表示文件描述符;參數 cmd 指定要進行的鎖操作,由於 fcntl() 函數功能比較多,這裏先介紹與文件鎖相關的三個取值 F_GETLK、F_SETLK 以及 F_SETLKW。這三個值均與 flock 結構有關。flock 結構如下所示:
flock 結構:
struct flock { ... short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Starting offset for lock */ off_t l_len; /* Number of bytes to lock */ pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */ ... }; |
在 flock 結構中,l_type 用來指明創建的是共享鎖還是排他鎖,其取值有三種:F_RDLCK(共享鎖)、F_WRLCK(排他鎖)和F_UNLCK(刪除之前建立的鎖);l_pid 指明瞭該鎖的擁有者;l_whence、l_start 和l_end 這些字段指明瞭進程需要對文件的哪個區域進行加鎖,這個區域是一個連續的字節集合。因此,進程可以對同一個文件的不同部分加不同的鎖。l_whence 必須是 SEEK_SET、SEEK_CUR 或 SEEK_END 這幾個值中的一個,它們分別對應着文件頭、當前位置和文件尾。l_whence 定義了相對於 l_start 的偏移量,l_start 是從文件開始計算的。
可以執行的操作包括:
- F_GETLK:進程可以通過它來獲取通過 fd 打開的那個文件的加鎖信息。執行該操作時,lock 指向的結構中就保存了希望對文件加的鎖(或者說要查詢的鎖)。如果確實存在這樣一把鎖,它阻止 lock 指向的 flock 結構所給出的鎖描述符,則把現存的鎖的信息寫到 lock 指向的 flock 結構中,並將該鎖擁有者的 PID 寫入 l_pid 字段中,然後返回;否則,就將 lock 指向的 flock 結構中的 l_type 設置爲 F_UNLCK,並保持 flock 結構中其他信息不變返回,而不會對該文件真正加鎖。
- F_SETLK:進程用它來對文件的某個區域進行加鎖(l_type的值爲 F_RDLCK 或 F_WRLCK)或者刪除鎖(l_type 的值爲F_UNLCK),如果有其他鎖阻止該鎖被建立,那麼 fcntl() 就出錯返回
- F_SETLKW:與 F_SETLK 類似,唯一不同的是,如果有其他鎖阻止該鎖被建立,則調用進程進入睡眠狀態,等待該鎖釋放。一旦這個調用開始了等待,就只有在能夠進行加鎖或者收到信號時纔會返回
需要注意的是,F_GETLK 用於測試是否可以加鎖,在 F_GETLK 測試可以加鎖之後,F_SETLK 和 F_SETLKW 就會企圖建立一把鎖,但是這兩者之間並不是一個原子操作,也就是說,在 F_SETLK 或者 F_SETLKW 還沒有成功加鎖之前,另外一個進程就有可能已經插進來加上了一把鎖。而且,F_SETLKW 有可能導致程序長時間睡眠。還有,程序對某個文件擁有的各種鎖會在相應的文件描述符被關閉時自動清除,程序運行結束後,其所加的各種鎖也會自動清除。
fcntl() 既可以用於勸告鎖,也可以用於強制鎖,在默認情況下,它用於勸告鎖。如果它用於強制鎖,當進程對某個文件進行了讀或寫這樣的系統調用時,系統則會檢查該文件的鎖的 O_NONBLOCK 標識,該標識是文件狀態標識的一種,如果設置文件狀態標識的時候設置了 O_NONBLOCK,則該進程會出錯返回;否則,該進程被阻塞。cmd 參數的值 F_SETFL 可以用於設置文件狀態標識。
3.1.2 Posix lock 內部機制:
1) 調用fcntl(fd, F_SETLK, &lock), fcntl()方法調用內核的do_fcntl()方法(linux/fs/fcntl.c)
static long do_fcntl(unsigned int fd, unsigned intcmd, unsigned long arg, struct file * filp)
{
switch (cmd) {
.....
case F_GETLK: /*Posix Lock 操作*/
err = fcntl_getlk(fd, (struct flock *) arg);
break;
case F_SETLK:
case F_SETLKW:
err = fcntl_setlk(fd, cmd, (struct flock *) arg);
break;
...
}
2) do_fcntl()裏調用fcntl_setlk()(linux/fs/flock.c)
int fcntl_setlk(unsigned int fd, struct file *filp,unsigned int cmd, struct flock __user *l)
{
structfile_lock *file_lock = locks_alloc_lock();
struct flock flock;
......
//把把客戶傳來的flock __user l拷貝爲flock
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
//把客戶傳來的flock的鎖l變爲file_lock
error =flock_to_posix_lock(filp, file_lock, &flock);
......
//阻塞的設置
if (cmd ==F_SETLKW) {
file_lock->fl_flags|= FL_SLEEP;
}
error = -EBADF;
//設置不同類型的鎖信息
switch(flock.l_type) {
case F_RDLCK:
if(!(filp->f_mode & FMODE_READ))
gotoout;
break;
case F_WRLCK:
if(!(filp->f_mode & FMODE_WRITE))
gotoout;
break;
case F_UNLCK:
break;
default:
error =-EINVAL;
goto out;
//鎖文件filp
error = do_lock_file_wait(filp, cmd, file_lock);
spin_lock(¤t->files->file_lock);
f = fcheck(fd);
spin_unlock(¤t->files->file_lock);
......
}
3) fcntl_setlk()調用do_lock_file_wait()
static int do_lock_file_wait(struct file *filp, unsignedint cmd, struct file_lock *fl)
{
......
error =security_file_lock(filp, fl->fl_type);
......
//關鍵
error =vfs_lock_file(filp, cmd, fl, NULL);
......
}
4) do_lock_file_wait()調用vfs_lock_file()
int vfs_lock_file(struct file *filp, unsigned int cmd,struct file_lock *fl, struct file_lock *conf)
{
if (filp->f_op&& filp->f_op->lock)
returnfilp->f_op->lock(filp, cmd, fl);
else
//關鍵
returnposix_lock_file(filp, fl, conf);
}
5) vfs_lock_file()調用posix_lock_file()
int posix_lock_file(struct file *filp, struct file_lock*fl, struct file_lock *conflock)
{
return__posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock);
}
6) posix_lock_file()調用__posix_lock_file()
__posix_lock_file()是真正鎖文件的函數,它具有檢測衝突鎖的功能。具體代碼看locks.c中的__posix_lock_file()。
大致流程是這樣:
遍歷inode->i_flock,找是POSIX鎖且有衝突的鎖(用posix_locks_conflict()函數),若存在或者有阻塞標誌或者死鎖了,做一定處理退出;若不存在這樣的鎖,就可以鎖文件。再次遍歷inode->i_flock,找到屬於自己進程的鎖,如果檢測到了鎖並判斷鎖類型,處理記錄相交的部分,設置鎖屬性,最後按照一定方式插入鎖;如果未檢測到鎖,則插入鎖。
3.1.3兩種鎖檢測衝突:
· 建議鎖(Advisory lock)
系統默認的鎖,檢測兩鎖是否衝突的函數:
posix_locks_conflict(structfile_lock *caller_fl, struct file_lock *sys_fl)函數過程:
先判斷兩把鎖是否屬於同一進程,自己不會和自己衝突。
如果它們兩是不同進程的鎖,判斷是否有鎖定區域重合。
· 強制性鎖(Mandatory lock)
檢測強制性鎖衝突的函數,滿足條件則加鎖,locks_mandatory_area()函數過程:
函數裏調用了posix_locks_conflict()用於判斷衝突鎖,調用__posix_lock_file()函數用於加鎖。
3.1.3 說明一個問題:如果文件被加了強制性鎖,爲什麼系統調用read(),write()就會受到限制?
看系統調用的read的實現方法:
1) 內核函數 sys_read() 是 read 系統調用在該層的入口點(read_write.c):
SYSCALL_DEFINE3(read, unsigned int, fd,char __user *, buf, size_t, count)
2) Sys_read()裏調用vfs_read()(read_write.c)
3) vfs_read()裏調用rw_verify_area(READ,file, pos, count);
4) rw_verify_area()調用了mandatory_lock()和locks_mandatory_area()(mandatory_lock在fs.h中,locks_mandatory_area在locks.c中)
5) mandatory_lock()調用了IS_MANDLOCK()和__mandatory_lock(),其中,IS_MANDLOCK()判斷文件系統是否有MS_MANDLOCK,__mandatory_lock()判斷文件是否setgid和去掉組執行位
6) locks_mandatory_area()檢查是否有鎖衝突,若有衝突,讀操作出錯。
結果:所以系統調用read就不能在有強制性鎖的情況下讀文件。Write和open是類似的道理。
3.2 flock的加鎖方法(flock):
3.2.1 使用介紹:
flock() 的函數原型如下所示:
int flock(int fd, int operation); |
其中,參數 fd 表示文件描述符;參數 operation 指定要進行的鎖操作,該參數的取值有如下幾種:LOCK_SH, LOCK_EX, LOCK_UN 和 LOCK_MANDphost2008-07-03T00:00:00
man page 裏面沒有提到,其各自的意思如下所示:
- LOCK_SH:表示要創建一個共享鎖,在任意時間內,一個文件的共享鎖可以被多個進程擁有
- LOCK_EX:表示創建一個排他鎖,在任意時間內,一個文件的排他鎖只能被一個進程擁有
- LOCK_UN:表示刪除該進程創建的鎖
- LOCK_MAND:它主要是用於共享模式強制鎖,它可以與 LOCK_READ 或者 LOCK_WRITE 聯合起來使用,從而表示是否允許併發的讀操作或者併發的寫操作(儘管在 flock() 的手冊頁中沒有介紹 LOCK_MAND,但是閱讀內核源代碼就會發現,這在內核中已經實現了)
通常情況下,如果加鎖請求不能被立即滿足,那麼系統調用 flock() 會阻塞當前進程。比如,進程想要請求一個排他鎖,但此時,已經由其他進程獲取了這個鎖,那麼該進程將會被阻塞。如果想要在沒有獲得這個排他鎖的情況下不阻塞該進程,可以將 LOCK_NB 和 LOCK_SH 或者 LOCK_EX 聯合使用,那麼系統就不會阻塞該進程。flock() 所加的鎖會對整個文件起作用。
說明:共享模式強制鎖可以用於某些私有網絡文件系統,如果某個文件被加上了共享模式強制鎖,那麼其他進程打開該文件的時候不能與該文件的共享模式強制鎖所設置的訪問模式相沖突。但是由於可移植性不好,因此並不建議使用這種鎖。
3.2.2 flock的內部機制:
flock和posix lock都共享一組機制,系統調用fcntl() 符合 POSIX 標準的文件鎖實現,功能比flock強大,可以支持記錄鎖。flock() 系統調用是從 BSD 中衍生出來的,只能支持整個文件的鎖。
flock_lock_file()與posix lock機制類似,詳細看代碼(locks.c)
3.3 lease鎖的方法:
3.3.1使用說明:
系統調用 fcntl() 還可以用於租借鎖,此時採用的函數原型如下:
int fcntl(int fd, int cmd, long arg); |
與租借鎖相關的 cmd 參數的取值有兩種:F_SETLEASE 和 F_GETLEASE。其含義如下所示:
- F_SETLEASE:根據下面所描述的 arg 參數指定的值來建立或者刪除租約:
- F_RDLCK:設置讀租約。當文件被另一個進程以寫的方式打開時,擁有該租約的當前進程會收到通知
- F_WRLCK:設置寫租約。當文件被另一個進程以讀或者寫的方式打開時,擁有該租約的當前進程會收到通知
- F_UNLCK:刪除以前建立的租約
- F_GETLEASE:表明調用進程擁有文件上哪種類型的鎖,這需要通過返回值來確定,返回值有三種:F_RDLCK、F_WRLCK和F_UNLCK,分別表明調用進程對文件擁有讀租借、寫租借或者根本沒有租借
某個進程可能會對文件執行其他一些系統調用(比如 OPEN() 或者 TRUNCATE()),如果這些系統調用與該文件上由 F_SETLEASE 所設置的租借鎖相沖突,內核就會阻塞這個系統調用;同時,內核會給擁有這個租借鎖的進程發信號,告知此事。擁有此租借鎖的進程會對該信號進行反饋,它可能會刪除這個租借鎖,也可能會減短這個租借鎖的租約,從而可以使得該文件可以被其他進程所訪問。如果擁有租借鎖的進程不能在給定時間內完成上述操作,那麼系統會強制幫它完成。通過 F_SETLEASE 命令將 arg 參數指定爲 F_UNLCK 就可以刪除這個租借鎖。不管對該租借鎖減短租約或者乾脆刪除的操作是進程自願的還是內核強迫的,只要被阻塞的系統調用還沒有被髮出該調用的進程解除阻塞,那麼系統就會允許這個系統調用執行。即使被阻塞的系統調用因爲某些原因被解除阻塞,但是上面對租借鎖減短租約或者刪除這個過程還是會執行的。
需要注意的是,租借鎖也只能對整個文件生效,而無法實現記錄級的加鎖。
採用強制鎖之後,如果一個進程對某個文件擁有寫鎖,只要它不釋放這個鎖,就會導致訪問該文件的其他進程全部被阻塞或不斷失敗重試;即使該進程只擁有讀鎖,也會造成後續更新該文件的進程的阻塞。爲了解決這個問題,Linux 中採用了一種新型的租借鎖。
當進程嘗試打開一個被租借鎖保護的文件時,該進程會被阻塞,同時,在一定時間內擁有該文件租借鎖的進程會收到一個信號。收到信號之後,擁有該文件租借鎖的進程會首先更新文件,從而保證了文件內容的一致性,接着,該進程釋放這個租借鎖。如果擁有租借鎖的進程在一定的時間間隔內沒有完成工作,內核就會自動刪除這個租借鎖或者將該鎖進行降級,從而允許被阻塞的進程繼續工作。
系統默認的這段間隔時間是 45 秒鐘,定義如下:
137 int lease_break_time = 45; |
這個參數可以通過修改 /proc/sys/fs/lease-break-time 進行調節(當然,/proc/sys/fs/leases-enable 必須爲 1 才行)。
3.3.2 leaseLock內部實現:
在fs/locks.c中:
fcntl_getlease():查詢目前活躍的租借鎖
fcntl_setlease():爲打開的文件設置一個租借鎖
__break_lease():這個函數是在open和truncate的時候進行的租約判定
第四節 測試結果
4.1 JAVA鎖、C鎖和系統之間的關係
JAVA是用文件Channel中的tryLock()和lock()方法來對文件加鎖。
下表是在建議鎖的情況下的測試結果:
JAVA和JAVA之間的鎖: l Test1程序先鎖住一個文件file1,Test2可以檢測到file1上有鎖。 l 在windows下,Test1程序先鎖住一個文件file1,Test2不可以直接讀寫文件,報異常:IOException。 l 在linux下,Test1程序先鎖住一個文件file1,Test2可以直接讀寫文件! |
JAVA和C之間的鎖: l 如果文件被加鎖,相互可以檢測到鎖的存在,但仍然可以直接往文件寫數據。 |
JAVA和系統之間的鎖: l 文件被加鎖,cp和vi等系統命令,仍然可以對文件進行讀寫。Vi很多版本用的是勸告鎖。 |
下表是在強制性鎖的情況下的測試結果:
JAVA和JAVA之間的鎖: l Java程序Test1先鎖住一個文件file1,Java程序Test2(lock)去鎖file1,則Test2會阻塞,直到Test2獲得鎖。 l Java程序Test1先鎖住一個文件file1,Java程序Test2(tryLock)去鎖file1,則Test2會報異常:FileNotFoundException。 l Java程序Test1先鎖住一個文件file1,Java程序Test2去讀file1文件,則Test2被阻塞,直到Test2獲得鎖,讀操作成功。 l Java程序Test1先鎖住一個文件file1,Java程序Test2去寫file1文件,則Test2被阻塞,直到Test2獲得鎖,寫操作成功。 |
JAVA和C之間的鎖: l 如果文件被c程序加鎖,java程序讀文件被阻塞,直到java程序獲得鎖,讀取成功。 l 如果文件被c程序加鎖,java程序寫文件被阻塞,直到java程序獲得鎖,寫入成功。 l 如果文件被java程序加鎖,c程序讀文件被阻塞,直到c程序獲得鎖,讀取成功。 l 如果文件被java程序加鎖,c程序寫文件被阻塞,直到c程序獲得鎖,寫入成功。
l 如果文件已被c程序加鎖,java程序用lock()方法也去鎖文件,java程序會阻塞,直到java程序獲得鎖。 l 如果文件已被c程序加鎖,java程序用tryLock()方法也去鎖文件,java程序報異常:FileNotFoundException。 l 如果文件已被java程序加鎖,c程序用F_SETLK方法也去鎖文件,c程序報打開錯誤(因爲去鎖文件,都需要有open獲得文件描述符fd)。 l 如果文件已被java程序加鎖,c程序用F_SETLKW方法也去鎖文件,c程序報打開錯誤(因爲去鎖文件,都需要有open獲得文件描述符fd)。 |
JAVA和系統之間的鎖: l cp命令: 1. java程序鎖住文件file1,系統命令cp file2 file1,返回錯誤: cannot create regular file `file1`: Resource temporarily unavailable 2. java程序鎖住文件file1,系統命令cp file1 file2,被阻塞,直到java程序獲得鎖,cp方可成功。 l vi命令: java程序鎖住文件file1,此時vi file1,被阻塞,直到vi獲得鎖,纔可打開文件。 |
參考文獻:
http://www.ibm.com/developerworks/cn/linux/l-cn-filelock/
http://www.linuxpk.com/archiver/tid-13992.html
http://www.ibm.com/developerworks/cn/linux/l-cn-read/
http://apps.hi.baidu.com/share/detail/46729488