编辑
2023-10-25
linux
00
请注意,本文编写于 562 天前,最后修改于 562 天前,其中某些信息可能已经过时。

下面来讲解一下文件锁有关的API,它是进程级别的锁。

  1. fcntl():控制文件描述符的属性。

    c
    #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ );
    • fd:文件描述符。
    • cmd:控制命令,可以是以下之一:
      • F_SETLK:设置锁(非阻塞)
      • F_SETLKW:设置锁(阻塞)
      • F_GETLK:获取锁信息
    • arg:命令的附加参数,可以是一个 struct flock 结构。

    返回值:

    • 成功时返回执行命令的结果(根据命令不同)。
    • 失败时返回 -1,并设置 errno
  2. struct flock:文件锁信息结构。

    c
    struct 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_SETSEEK_CURSEEK_END
    • l_start:锁的起始偏移量。
    • l_len:锁的长度,0 表示锁住整个文件。
    • l_pid:持有锁的进程ID,F_GETLK 命令返回时会填充。
  3. 文件锁类型

    • 读锁(F_RDLCK):允许其他进程获取读锁,但阻止其他进程获取写锁。
    • 写锁(F_WRLCK):阻止其他进程获取读锁和写锁。
    • 解锁(F_UNLCK):释放文件上的锁。

以下是演示:

进程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会阻塞

image.png

你也可以用信号量来进行模拟文件锁操作,还有共享内存等,锁就是一个与各自状态无关联且双方都能够访问的变量。

本文作者:yowayimono

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!