如果对一个文件的同一个区域同时读和写,则会发生冲突,导致读和写发生错误,所以要使用文件锁对其进行锁定。
当我们对一个文件写入时,其他进程对其不能进行操作,而对其读时,其他进程不可以写但是可以读。即写独占,读共享。
因此,读锁相当于一个共享锁,对于一个文件的一个区域可以同时加多把锁。而对于一个写锁,对于某个文件只能在一个区域加入一把锁。
使用函数: int fcntl(int fd, F_SETLK/F_SETLKW, struct flock *lock);
fd:文件描述符。
F_SETLKW/F_SETLK:是否需要阻塞锁。
flock为一个结构体:
struct flock{
short int l_type; //锁的类型,包括F_RDLCK, F_WRLCK, F_UNLCK
short int l_whence; //锁的偏移地点,包括:SEEK_SET, SEEK_CUR, SEEK_END
off_t l_start; //锁的偏移
off_t l_len //锁区的长度
pid_t l_pid //加锁进程的pid, -1代表自动设置
}
如果我们对于文件头10个字节开始,加一个长度为20字节的阻塞模式的读锁,应该为:
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 10;
lock.l_len = 20;
lock.l_pid = -1;
fcntl(fd, F_SETLKW, &lock);
实例代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
// 加读锁
int rlock(int fd, off_t start, off_t len,
int wait) {
struct flock lock;
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = len;
lock.l_pid = -1;
return fcntl(fd, wait ? F_SETLKW : F_SETLK,
&lock);
}
// 加写锁
int wlock(int fd, off_t start, off_t len,
int wait) {
struct flock lock;
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = len;
lock.l_pid = -1;
return fcntl(fd, wait ? F_SETLKW : F_SETLK,
&lock);
}
// 解除锁
int ulock(int fd, off_t start, off_t len) {
struct flock lock;
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = start;
lock.l_len = len;
lock.l_pid = -1;
return fcntl(fd, F_SETLK, &lock);
}
int main(void) {
printf("进程标识(PID):%d\n", getpid());
int fd = open("shared.txt", O_RDWR |
O_CREAT | O_TRUNC, 0644);
if (fd == -1) {
perror("open");
return -1;
}
const char* text = "ABCDEFGHIJKLMNOPQRST";
if (write(fd, text, strlen(text) * sizeof(
text[0])) == -1) {
perror("write");
return 0;
}
printf("对EFGH加读锁");
if (rlock(fd, 4, 4, 0) == -1) {
printf("失败:%m\n");
return -1;
}
printf("成功!\n");
printf("对MNOP加写锁");
if (wlock(fd, 12, 4, 0) == -1) {
printf("失败:%m\n");
return -1;
}
printf("成功!\n");
printf("按<回车>,解锁MN...");
getchar();
ulock(fd, 12, 2);
printf("按<回车>,解锁EFGH...");
getchar();
ulock(fd, 4, 4);
close(fd);
return 0;
}