对文件加锁时可以加两种锁,分别是“读文件锁”和“写文件锁”,简称读锁和写锁。
对整个文件的内容加锁
对整个文件加锁是最常用的文件加锁方式。
当你整个文件加锁时,如果文件的长度因为写入新数据或者截短而发生了变化,加锁内容长度会自动变化,保证对内容变化着的整个文件加锁。
对文件某部分内容加锁
不过一般来说,对多少内容加锁,就对多少内容解锁。如果你是对整个文件加锁,就将整个文件解锁。
但是实际上加锁和实际解锁的长度不相同,比如我对1000个字节的内容加了锁,但是只对其中的100字节解锁,不过这种情况用的少,知道怎么回事即可。
怎么实现文件的整个加锁和区域解锁呢?
后面再说
int fcntl(int fd, int cmd, ... /* struct flock *flockptr */ );
第三个参数是...,fcntl函数是一个变参函数,第三个参数用不到时就不写
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
(set by F_GETLK and F_OFD_GETLK) */
...
};
成员说明:
l_type:锁类型
l_whence:加锁位置粗定位,设置同lseek的whence
l_start:精定位,相对于l_whence的偏移,与lseek的offset的含义完全一致
通过l_whence和l_start的值,就可以用来指定从文件的什么位置开始加锁,不过一般来说,我们会将l_whence指定为SEEK_SET,l_start指定为0,表示从整个文件头上开始加锁。
l_len:从l_whence和l_start所指定的起始地点算起,需要对文件多长的内容加锁。
如果 l_len被设置0,表示一直加锁到文件结尾,如果文件长度时变化的,将自动调整加锁的末尾位置。
将l_whence和l_start设置为SEEK_SET和0,然后再将l_len设置为0,就表示从文件加锁到文件末尾,其实就是对整个文件加锁。
如果只是对文件中间的某段加锁,这只是区域加锁,加区域锁时可以给文件n多个的独立区域加锁。
l_pid:当前正加锁进程的PID
使用文件锁的互斥操作,解决父子进程向同一文件写"hello",“world\n”时,hello hello world相连的问题。
头文件,学到了封装函数的思想,尤其是使用宏来实现不同类型的文件锁
/* Too many parameters ,Different types of locks
* Write dead!!!!!!!!!
* */
/* Set non blocking write lock */
#define SET_WRFLCK(fd, l_whence, l_start, l_len) \
set_filelock(fd, F_SETLK, F_WRLCK, l_whence, l_start, l_len)
/* Set blocking write lock */
#define SET_WRFLCKW(fd, l_whence, l_start, l_len) \
set_filelock(fd, F_SETLKW, F_WRLCK, l_whence, l_start, l_len)
/* Set blocking read lock */
#define SET_RDFLCKW(fd, l_whence, l_start, l_len) \
set_filelock(fd, F_SETLKW, F_RDLCK, l_whence, l_start, l_len)
/* Set nonblocking read lock */
#define SET_RDFLCK(fd, l_whence, l_start, l_len) \
set_filelock(fd, F_SETLK, F_RDLCK, l_whence, l_start, l_len)
/* Unlock */
#define SET_UNFLCK(fd, l_whence, l_start, l_len) \
set_filelock(fd, F_SETLK, F_UNLCK, l_whence, l_start, l_len)
/*Package and set the locking function
* */
static void set_filelock(int fd, int ifwait, short l_type, short l_whence, off_t l_start, short l_len)
{
int ret = 0;
struct flock flock;
flock.l_type = l_type;
flock.l_whence = l_whence;
flock.l_start = l_start;
flock.l_len = l_len;
ret = fcntl(fd, ifwait, &flock);
if (ret == -1)
{
perror("fcntl");
exit(EXIT_FAILURE);
}
}
int main(int argc, char *argv[])
{
int fd = 0;
int ret = 0;
fd = open("./hello", O_RDWR|O_CREAT|O_TRUNC, 0664);
if (fd == -1) print_err("./hello", __LINE__, errno);
ret = fork();
if (ret > 0)
{
while(1)
{
SET_WRFLCKW(fd, SEEK_SET, 0, 0);
write(fd, "hello ", 6);
write(fd, "world\n", 6);
SET_UNFLCK(fd, SEEK_SET, 0, 0);
}
}
else if (ret == 0)
{
while(1)
{
SET_WRFLCKW(fd, SEEK_SET, 0, 0);
write(fd, "hello ", 6);
write(fd, "world\n", 6);
SET_UNFLCK(fd, SEEK_SET, 0, 0);
}
}
return 0;
}
在hello文件里面使用/hello hello没找到文本内容说明成功了。
对于fcntl的认识不仅仅可以追加改变文件标志,还可以实现文件锁的功能