当使用fcntl对文件加锁时,函数原型为:
int fcntl(fd,cmd,struct flock *);
其中fd表示文件描述符,cmd表示命令字(有F_SETLK,F_SETLKW,F_GETLK),第三个是一个文件锁的结构体指针。
struct flock结构体如下:
struct flock
{
short l_type, /*F_RDLCK F_WRLCK F_UNLCK*/
off_t l_start, /*偏移量,相对于l_whence的偏移量*/
short l_whence, /*SEEK_SET SEEK_CUR SEEK_END*/
off_t l_len, /*被加锁区间的长度,0意味着加锁直到EOF,当文件追加时,追加部分也被加锁*/
pid_t l_pid, /*当cmd为F_GETLK时,l_pid字段,将用对方的进程pid填充*/
};
新锁替换老锁:
如果一个进程对文件区间已经加锁,后来该进程又企图在同一文件区域再加一把锁,那么新锁将替换老锁。
F_GETLK不能获取当前进程的锁状态,所以使用F_GETLK必须注意:
F_GETLK的只用必须注意,一个进程不能使用F_GETLK函数来测试自己是否在文件的某一部分持有一把锁。
F_GETLK命令定义说明,F_GETLK返回信息指示是否有现存的锁阻止调用进程设置自己的锁。(也就是说,F_GETLK会尝试加锁,以判断是否有进程阻止自己在设定的区域加锁,如果有,就将l_type设置为F_UNLCK,将l_pid设置为加锁进程的PID)。但是由于对于当前进程,新锁替换老锁,所以调用进程决不会阻塞在自己持有的锁上加锁。所以F_GETLK命令决不会报告调用进程自己持有的锁。
锁的隐含继承和释放:
一、锁与进程和文件的关系:
1、当一个进程终止时,它所建立的锁全部释放。(进程退出,文件描述符由系统关闭)
2、任何时候关闭一个文件描述符时,则该进程通过这个描述符可以引用的文件上的所有锁,都被释放。因为这些锁都是当前进程设置的。(关闭文件描述符,加载文件上的锁被释放)
含义如下:
fd1 = open(pathname,...);
read_lock(fd1);
fd2 = dup(fd1);
close(fd2); //此时在pathname上的所有当前进程加的锁都被释放
fd1 = open(pathname,...);
read_lock(fd1,...);
fd2 = open(pathname,...);
close(fd2); //此时在pathname上的所有当前进程加的锁都被释放
二、锁与fork的关系:
fork出来的子进程不能继承父进程的锁。当fork出来的进程可以继承父进程的文件描述符。
三、锁与exec的关系:
exec执行新程序后,新程序将继承exec之前当前进程设置的锁。当时exec执行的新程序不能继承exec之前当前进程打开的文件描述符(都被关闭了)。当设置了close-on-exec后,锁就不能被exec执行的新程序继承。
锁的简单应用:
1、对整个文件上加写锁。
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_sart = 0;
fl.l_whence = SEEKSET;
fl.l_len = 0; //意味着加锁一直加到EOF
fcntl(fd,F_SETLK,&fl);
2、对整体文件加写锁后(如上面),当有数据追加到文件中时,追加进来的部分也是被加锁的。