文件锁
概念
- 在多进程对同一个文件进行读写访问时,为了保证数据的完整性,有时需要对文件进行锁定。
- 可以通过fcntl()函数对文件进行锁定和解锁。
写锁(F_WRLCK独占锁)
- 只有一个进程可以在文件的任一特定区域上享有独占锁。
读锁(F_RDLCK共享锁)
- 许多不同的进程可以同时拥有文件上同一区域上的共享锁。
为了拥有共享锁,文件必须以 读 或者 读/写 的方式打开。只要任一进程拥有共享锁,那么其他进程就无法再获得独占锁。
flock()
- 对整个文件进行操作
#include <sys/file.h>
int flock(int fd, int operation);
- fd:文件描述符
- operation 取值情况:
- LOCK_SH:放置共享锁。在给定时间,多个进程可能持有给定文件的共享锁。
- LOCK_EX:放置独占锁。在给定时间,只有一个进程可以为给定文件持有独占锁。
- LOCK_UN:移除此进程持有的现有锁。
fcntl()
- 可以对文件部分区域放锁。(精细版)
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
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) */
...
};
- 可变参数传struct flock结构体。
设置读锁
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main() {
int fd = open("./hello.txt", O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
struct stat st;
fstat(fd, &st);
struct flock fl;
fl.l_pid = getpid();
fl.l_type = F_RDLCK;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = st.st_size;
printf("pid: %d ", fl.l_pid);
if (fcntl(fd, F_SETLK, &fl) < 0) {
perror("fcntl");
exit(1);
} else {
printf("add read lock successfully\n");
}
sleep(10);
close(fd);
return 0;
}
设置写锁
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
int main() {
int fd = open("./hello.txt", O_WRONLY); //只写
if (fd < 0) {
perror("open");
exit(1);
}
struct stat st;
fstat(fd, &st); // 获取文件信息
struct flock fl;
fl.l_pid = getpid();
fl.l_type = F_WRLCK; //设置写锁
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = st.st_size;
printf("pid: %d ", fl.l_pid);
while (fcntl(fd, F_SETLK, &fl) < 0) {
perror("fcntl");
struct flock fl2;
fl2 = fl;
fl2.l_type = F_WRLCK;
fcntl(fd, F_GETLK, &fl2); //得到锁的信息
switch (fl2.l_type) {
case F_UNLCK:
printf("get no lock\n");
break;
case F_RDLCK:
printf("get read lock of pid = %d\n", fl2.l_pid);
break;
case F_WRLCK:
printf("get write lock of pid = %d\n", fl2.l_pid);
break;
}
sleep(1);
}
printf("add write lock successfully\n");
getchar();
close(fd);
return 0;
}