作用
记录锁与读写锁很相似, 记录锁也分读和写两种操作, 但它们的作用对象分别是进程和线程.
多个进程对同一文件进行访问时,记录锁可以锁定文件的某一个区间,以读操作锁定时允许其它进程进行继续加读锁, 以写操作锁定时不允许其它进程添加读锁或写锁.
记录锁只对加锁的函数fcntl进行检测, 如果其它进程不按先加锁后读写的顺序进行访问则记录锁不起作用.
在一些系统上将组权限位打开, 同时关闭组执行位可强制所有读写函数进行锁检查.
基本函数
#include <fcntl.h>
int fcntl(int fd, int cmd, struct flock *lock);
cmd = F_GETLK //获取文件当前锁的状态,第三个参数作为输出
cmd = F_SETLK //设置锁,第三个参数作为输入
cmd = F_SETLKW //阻塞设置一把锁,第三个参数作为输入
struct flock {
short l_type; /* 锁的类型: F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence; /* 加锁的起始位置:SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* 加锁的起始偏移,相对于l_whence */
off_t l_len; /* 上锁的字节数*/
pid_t l_pid; /* 已经占用锁的PID(只对F_GETLK 命令有效) */
/*...*/
};
例子
#include "unpipc.h"
int lock_reg(int fd,int cmd,int type,off_t offset,int whence,off_t len){
struct flock lock;
lock.l_type=type;
lock.l_start=offset;
lock.l_whence=whence;
lock.l_len=len;
return(fcntl(fd,cmd,&lock));
}
pid_t lock_test(int fd,int type,off_t offset,int whence,off_t len){
struct flock lock;
lock.l_len=len;
lock.l_type=type;
lock.l_whence=whence;
lock.l_len=len;
if(fcntl(fd,F_GETLK,&lock) == -1)
return(-1);
if(lock.l_type == F_UNLCK)
return(0);
return(lock.l_pid);
}
#define read_lock(fd,offset,whence,len)
lock_reg(fd,F_SETLK,F_RDLCK,offset,whence,len)
#define readw_lock(fd,offset,whence,len)
lock_reg(fd,F_SETLKW,F_RDLCK,offset,whence,len)
#define write_lock(fd,offset,whence,len)
lock_reg(fd,F_SETLK,F_WRLCK,offset,whence,len)
#define writew_lock(fd,offset,whence,len)
lock_reg(fd,F_SETLKW,F_WRLCK,offset,whence,len)
#define un_lock(fd,offset,whence,len)
lock_reg(fd,F_SETLK,F_UNLCK,offset,whence,len)
#define is_read_lockable(fd,offset,whence,len)
!lock_test(fd,F_RDLCK,offset,whence,len)
#define is_write_lockable(fd,offset,whence,len)
!lock_test(fd,F_WRLCK,offset,whence,len)
int main(int argc, char *argv[]){
pid_t pid;
int fd=Open("./lock.c",O_RDWR,0777);
if((pid=Fork())==0){
if(read_lock(fd,0,SEEK_SET,1) == -1)
err_quit("child read_lock error");
puts("child read_lock file");
sleep(3);
puts("child un_lock file");
un_lock(fd,0,SEEK_SET,1);
}else{
sleep(1);
if(write_lock(fd,0,SEEK_SET,1) == -1)
puts("father write_lock failed, waiting for child un_lock");
if(writew_lock(fd,0,SEEK_SET,1) == -1)
puts("father writew_lock error");
puts("father got write lock");
un_lock(fd,0,SEEK_SET,1);
waitpid(pid,NULL);
}
exit(0);
}