下面来讲解一下文件锁有关的API,它是进程级别的锁。
fcntl()
:控制文件描述符的属性。
c#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
fd
:文件描述符。cmd
:控制命令,可以是以下之一:
F_SETLK
:设置锁(非阻塞)F_SETLKW
:设置锁(阻塞)F_GETLK
:获取锁信息arg
:命令的附加参数,可以是一个 struct flock
结构。返回值:
errno
。struct flock
:文件锁信息结构。
cstruct flock {
short l_type; // 锁的类型:F_RDLCK、F_WRLCK、F_UNLCK
short l_whence; // 偏移量起点:SEEK_SET、SEEK_CUR、SEEK_END
off_t l_start; // 锁的起始偏移量
off_t l_len; // 锁的长度,0 表示锁住整个文件
pid_t l_pid; // 持有锁的进程ID(F_GETLK 命令返回)
};
l_type
:锁的类型,可以是 F_RDLCK
(读锁)、F_WRLCK
(写锁)、F_UNLCK
(解锁)。l_whence
:偏移量起点,如 SEEK_SET
、SEEK_CUR
、SEEK_END
。l_start
:锁的起始偏移量。l_len
:锁的长度,0 表示锁住整个文件。l_pid
:持有锁的进程ID,F_GETLK
命令返回时会填充。文件锁类型:
以下是演示:
进程1 - 写入数据:
c#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("file_lock_example.txt", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("打开文件失败");
exit(1);
}
struct flock lock;
lock.l_type = F_WRLCK; // 写锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁住整个文件
printf("进程1 尝试获取写锁...\n");
if (fcntl(fd, F_SETLKW, &lock) == -1) {
perror("获取写锁失败");
exit(1);
}
printf("进程1 获取写锁成功,写入数据...\n");
sleep(30); // 模拟写入数据的耗时操作
lock.l_type = F_UNLCK; // 解锁
if (fcntl(fd, F_SETLKW, &lock) == -1) {
perror("解锁失败");
exit(1);
}
close(fd);
return 0;
}
进程2 - 读取数据:
c#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("file_lock_example.txt", O_RDONLY);
if (fd == -1) {
perror("打开文件失败");
exit(1);
}
struct flock lock;
lock.l_type = F_RDLCK; // 读锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁住整个文件
printf("进程2 尝试获取读锁...\n");
if (fcntl(fd, F_SETLKW, &lock) == -1) {
perror("获取读锁失败");
exit(1);
}
printf("进程2 获取读锁成功,读取数据...\n");
sleep(2); // 模拟读取数据的耗时操作
lock.l_type = F_UNLCK; // 解锁
if (fcntl(fd, F_SETLKW, &lock) == -1) {
perror("解锁失败");
exit(1);
}
close(fd);
return 0;
}
当某个进程获取一个文件的写锁,这个文件就会被锁死,其他进程无法获取他的锁,包括写锁读锁,所以上面进程2会阻塞
你也可以用信号量来进行模拟文件锁操作,还有共享内存等,锁就是一个与各自状态无关联且双方都能够访问的变量。
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!