作用:
(實現文件的讀寫同步)當一個進程正在讀或修改文件的某個部分時,阻止其他進程修改同一文件區。
訪問操作:
寫入鎖——又叫排它鎖
讀取鎖——又叫共享鎖
多進程訪問
(同一個進程訪問只會覆蓋已有的鎖)
已存在鎖 讀取鎖 寫入鎖
無 OK OK
讀取鎖 OK NG
寫入鎖 NG NG
同一個進程訪問只會覆蓋已有的鎖
在訪問之前嘗試加鎖可以知道文件是否正在被讀寫。
加鎖區域:
文件鎖————整個文件上鎖
記錄鎖————文件部分內容上鎖
建議性鎖:
別名——勸解鎖/勸告鎖(寫鎖)和協同鎖/協作鎖(讀鎖)。
每個使用上鎖文件的進程都要檢查是否有鎖存在,要尊重已有的鎖。
要靠程序員遵守和實現。(不檢查是否有鎖的情況下可以強行讀寫)
強制性鎖:
——當文件被上鎖來進行寫入操作時,在鎖定該文件的進程釋放該鎖之前,內核會阻止任何對該文件的讀或寫訪問(open,read,write),每次讀寫訪問都要檢查鎖是否存在。
本質:
——內核讀寫文件自動處理。(內核實現,系統開銷大,影響性能,兼容性差)
設置:
1.重新掛載mount系統分區———sudo mount -o remount,mand/
mand———允許強制鎖定
nomand——進制強制鎖定
2.修改文件權限————————sudo chmod g+s,g-x 文件
在文件執行時把進程的組ID置爲該文件的文件屬性。
系統 建議性鎖 強制性鎖
Linux2.4.22 支持 支持
Solaris 9 支持 支持
Mac OS X 10.3 支持 不支持
FreeBSD 5.2.1 支持 不支持
建議性鎖函數:
int fcntl(int filedes,int cmd,...,);
鎖操作形式:
int fcntl(int fd,int cmd,struct flock* lock);
fd——文件描述符
cmd——命令:
獲取:F_GETLK
設置:
F_SETLK———加解鎖
F_SETLKW——加解鎖阻塞
struct flock{
l_type;
l_whence;
l_start;——相對l_whence位置的偏移量
l_len;——鎖定區域的長度
l_pid;——當前佔用鎖的PID(只能用F_GETLK命令獲取)
};
l_type:
F_RDLCK——讀鎖
F_WRLCK——寫鎖
F_UNLCK——解鎖
l_whence:
SEEK_SET——以文件開頭爲鎖定的起始位置
SEEK_CUR——以目前文件讀寫位置爲鎖定的起始位置
SEEK_END——以文件結尾爲鎖定的起始位置
返回值:
-1——失敗
0——SET相關命令成功
代碼:
讀鎖:
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char* argv[]){
if(2!=argc){
printf("usage:%s <pathname>\n",argv[0]);
return 1;
}
int fd = open(argv[1],O_RDONLY);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLK,&lock)){
perror("fcntl error");
return 1;
}
pause();
close(fd);
}
解鎖(只能在加鎖的進程中解鎖):
// 本程序不能解鎖,因爲只有加鎖進程才能執行解鎖操作
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char* argv[]){
if(2!=argc){
printf("usage:%s <pathname>\n",argv[0]);
return 1;
}
int fd = open(argv[1],O_WRONLY);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
return 1;
}
pause();
close(fd);
}
寫鎖+解鎖:
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int fd;
void handler(int sig){
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
exit(1);
}
}
int main(int argc, char* argv[]){
signal(SIGUSR1,handler);//用kill -s USR1 進程PID來傳輸信號。
int c,start = 0,len = 0;
while((c = getopt(argc,argv,"s:l:"))!=-1){
switch(c){
case 's':
start = atoi(optarg);
break;
case 'l':
len = atoi(optarg);
break;
}
}
if(optind != argc -1){
printf("usage:%s [-s <start>] [-l <len>] <pathname>\n",argv[0]);
return 1;
}
fd = open(argv[optind],O_WRONLY);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = len;
if(-1 == fcntl(fd,F_SETLKW,&lock)){
perror("fcntl error");
return 1;
}
pause();
for(;;);
close(fd);
}
查看上鎖情況:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char* argv[]){
if(2!=argc){
printf("usage:%s <pathname>\n",argv[0]);
return 1;
}
int fd = open(argv[1],O_RDWR);
if(-1 == fd){
perror("open error");
return 1;
}
struct flock lock;
bzero(&lock,sizeof(lock));
if(-1 == fcntl(fd,F_GETLK,&lock)){
perror("fcntl error");
return 1;
}
printf("file:%s,lock type:%d,start:%d,len:%d,by %d\n",argv[1],lock.l_type,lock.l_start,lock.l_len,lock.l_pid);
}