當多個用戶共同使用、操作一個文件的情況下,這時,Linux通常採用的方法是給文件上鎖,來避免共享的資源產生競爭的狀態。
文件鎖包括建議性鎖和強制性鎖。
建議性鎖要求每個上鎖文件的進程都要檢查是否有鎖存在,並且尊重已有的鎖。在一般情況下,內核和系統都不使用建議性鎖。
強制性鎖是由內核執行的鎖,當一個文件被上鎖進行寫入操作的時候,內核將阻止其它任何文件對其進行讀寫操作。採用強制性鎖對性能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。
在Linux中,實現文件上鎖的函數有lock和fcntl,其中flock用於對文件施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強制性鎖,還能對文件的某一記錄進行上鎖,也就是記錄鎖。
記錄鎖又分爲讀取鎖和寫入鎖。
讀取鎖又稱共享鎖,能使多個進程都在文件的同一部分建立讀取鎖。
寫入鎖又稱爲排斥鎖,在任何時刻只能有一個進程在文件的某個部分建立寫入鎖。
在文件的同一部分不能同時建立讀取鎖和寫入鎖。
(2)fcntl函數格式
Fcntl函數語法要點:
所需頭文件:#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
函數原型:int fcntl(int fd,cmd,struct flock *lock)
函數傳入值:fd:文件描述符
Cmd:F_DUPFD:複製文件描述符
F_GETFD:獲得fd的close-on-exec標誌,若標誌未設置,則文件經過exec函數之後仍保持打開狀態。
F_SETFD:設置close-on-exec標誌,該標誌以參數arg的FD_CLOEXEC位決定。
F_GETFL:得到open設置的標誌
F_SETFL:改變open設置的標誌
F_GETFK:根據lock描述,決定是否上文件鎖
F_SETFK:設置lock描述的文件鎖
F_SETLKW:這是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果存在其它鎖,則調用進程睡眠;如果捕捉到信號則睡眠中斷
F_GETOWN:檢索將收到SIGIO和SIGURG信號的進程號或進程組號
F_SETOWN:設置進程號或進程組號
Lock:結構爲flock,設置記錄鎖的具體狀態
函數返回值:成功:0
-1:出錯
Lock的結構如下所示:
Struct flock{
Short l_type;
Off_t l_start;
Short l_whence;
Off_t l_len;
Pid_t l_pid;
}
Lock結構變量取值:
L_type:F_RDLCK:讀取鎖(共享鎖)
F_WRLCK:寫入鎖(排斥鎖)
F_UNLCK:解鎖
L_stat:相對位移量(字節)
L_whence:相對位移量的起點(同lseek的whence):SEEK_SET:當前位置爲文件開頭,新位置爲偏移量的大小
SEEK_CUR:當前位置爲文件指針位置,新位置爲當前位置加上偏移量
SEEK_END:當前位置爲文件的結尾,新位置爲文件的大小加上偏移量大小
L_len:加鎖區域長度
(3)fcntl使用實例
Lock_set函數:
void lock_set(int fd,int type)
{
struct flock lock;
lock.l_whence=SEEK_SET;//賦值lock結構體
lock.l_start=0;
lock.l_len=0;
while(1)
{
lock.l_type=type;
/*根據不同的type值給文件上鎖或解鎖*/
if((fcntl(fd,F_SETLK,&lock))==0)
{
if(lock.l_type==F_RDLCK)
printf("read lock set by %d\n",getpid());
else if(lock.l_type=F_WRLCK)
printf("write lock set by %d\n",getpid());
else if(lock.l_type=F_UNLCK)
printf("release lock set by %d\n",getpid());
return;
}
/*判斷文件是否可以上鎖*/
fcntl(fd,F_GETLK,&lock);
/*判斷文件不能上鎖原因*/
if(lock.l_type!=F_UNLCK)
{
/*該文件已有寫入鎖*/
if(lock.l_type==F_RDLCK)
printf("read lock already set by %d\n",lock.l_pid());
/*該文件已有讀取鎖*/
else if(lock.l_type=F_WRLCK)
printf("write already lock set by %d\n", lock.l_pid ());
getchar();
}
}
}
/*fcntl_write.c測試文件寫入鎖函數部分*/
#include<unistd.h>
#include<sys/file.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int fd;
fd=open("hello",O_RDWR|O_CREAT,0666);
if(fd<0)
{
perror("open");
exit(1);
}
lock_set(fd,F_WRLCK);
getchar();
lock_set(fd,F_UNLCK);
getchar();
close(fd);
exit(0);
}