大家好,又见面了,我是你们的老朋友全栈君。
- 文件锁的基本概念
在Linux系统中,软件和硬件资源都被视为文件(即“一切皆文件”)。在多用户环境下,这些文件是可以共享的。
文件锁是一种机制,用于解决多个用户共享文件时的资源竞争问题:当多个用户需要访问同一个文件时,Linux通常会通过对文件加锁来避免资源竞争。
文件锁分为建议性锁和强制性锁:
建议性锁:要求每个使用锁定文件的进程都必须检查是否已有锁存在,并且遵守已有锁的存在。通常,内核和系统不会强制执行建议性锁,而是依赖程序员遵守规则。
强制性锁:由内核执行。当文件被锁定用于写入时,内核将阻止其他任何对该文件的读写操作。强制性锁对系统性能有显著影响,因为每次读写操作都需要检查锁的存在。
在Linux中,实现文件锁的函数有lockf()和fcntl()。lockf()用于设置建议性锁,而fcntl()不仅能设置建议性锁,还能设置强制性锁。fcntl()还可以对文件的特定记录进行锁定,即记录锁。
记录锁分为读取锁和写入锁。读取锁又称共享锁,允许多个进程在文件的同一部分建立读取锁。写入锁又称排他锁,任何时刻只能有一个进程在文件的某个部分建立写入锁。同一文件部分不能同时存在读取锁和写入锁。
fcntl()函数的格式如下:
#include#include #include int fcntl(int fd, int cmd, ...); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock);
fcntl()函数的参数包括:
-
fd:被操作的文件描述符。 -
cmd:命令类型,包括:-
F_DUPFD:复制现有描述符。 -
F_GETFD:获取fd的close-on-exec标志。 -
F_SETFD:设置close-on-exec标志。 -
F_GETFL:获取open设置的标志。 -
F_SETFL:更改open设置的标志。 -
F_GETLK:根据lock参数值,决定是否可以上文件锁。 -
F_SETLK:设置lock参数值的文件锁。 -
F_SETLKW:F_SETLK的阻塞版本。
-
close_on_exec是一个进程所有文件描述符的位图标志,用于在调用execve()时决定哪些文件描述符需要关闭。
fcntl()函数的返回值取决于第二个参数cmd,成功时返回值不同,失败时返回-1。

fcntl()的使用实例:
首先为flock结构体的相应字段赋值,然后使用fcntl()函数两次,分别用于判断文件是否可以上锁和对文件上锁,使用的cmd值分别为F_GETLK和F_SETLK(或F_SETLKW)。使用F_GETLK命令判断是否可以进行flock结构所描述的锁操作:如果可以加锁,flock结构的l_type会被设置为F_UNLCK,其他域保持不变;否则,l_pid被设置为拥有文件锁的进程号,l_type被设置为已有锁的类型,其他域保持不变。
- 写入锁
mylock.h:
int lock_set(int fd, int type) {
struct flock old_lock, lock;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_type = type;
lock.l_pid = -1;
fcntl(fd, F_GETLK, &lock);
if (lock.l_type != F_UNLCK) {
if (lock.l_type == F_RDLCK) {
printf("Read lock already set by %d\n", lock.l_pid);
} else if (lock.l_type == F_WRLCK) {
printf("Write lock already set by %d\n", lock.l_pid);
}
}
lock.l_type = type;
if ((fcntl(fd, F_SETLKW, &lock)) < 0) {
perror("fcntl");
exit(1);
}
return 0;
}write_lock.c:
#include#include #include #include #include #include #include "mylock.h" int main(void) { int fd; fd = open("hello", O_RDWR | O_CREAT, 0644); if (fd < 0) { perror("open"); exit(1); } lock_set(fd, F_WRLCK); printf("Write lock set\n"); sleep(20); lock_set(fd, F_UNLCK); close(fd); return 0; }


写入锁是互斥锁,同一时刻只能有一个写操作成功。
- 读锁测试
#include#include #include #include #include #include #include "mylock.h" int main(void) { int fd; fd = open("hello", O_RDWR | O_CREAT, 0644); if (fd < 0) { perror("open"); exit(1); } lock_set(fd, F_RDLCK); printf("Read lock set\n"); sleep(20); lock_set(fd, F_UNLCK); close(fd); return 0; }

读锁是共享锁,允许多个进程同时读取文件。
参考资料:
https://www.php.cn/link/103c95b905e20d63a6354e5284922bd2
发布者:全栈程序员栈长,转载请注明出处:https://www.php.cn/link/89a183c0c11d6d0ca7830f9d530a3097
原文链接:https://www.php.cn/link/c8377ad2a50fb65de28b11cfc628d75c










