文件锁技术详解:flock与fcntl系统调用
文件锁技术详解:flock与fcntl系统调用
一、flock系统调用
1.1 功能描述
flock()
提供文件级全局锁机制,可对整个文件施加共享锁或互斥锁。该锁为建议性锁(需主动检查),常用于进程间同步文件访问,但不保证强制排他性。
1.2 函数声明
#include <sys/file.h>
int flock(int fd, int operation);
1.3 参数详解
参数 | 类型 | 说明 | |
---|---|---|---|
fd | int | 文件描述符,需通过open() 或fileno(FILE*) 获取 | |
operation | int | 锁操作类型,支持以下宏组合: | |
- LOCK_SH :共享锁(允许多进程并发读) | |||
- LOCK_EX :互斥锁(仅允许单进程读写) | |||
- LOCK_UN :释放锁 | |||
- LOCK_NB :非阻塞模式(与上述宏用 ` | ` 组合,锁冲突时立即返回) |
1.4 返回值
• 成功:返回0
• 失败:返回-1
,错误码存于errno
,常见错误:
• EAGAIN
:非阻塞模式下锁冲突
• EBADF
:无效文件描述符
• EINTR
:被信号中断
二、fcntl系统调用
2.1 功能描述
fcntl()
支持记录级细粒度锁,可对文件指定区域加锁。提供强制锁与建议锁两种模式(依赖文件系统支持),具备更精细的控制能力。
2.2 函数声明
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, struct flock *lock);
2.3 参数详解
参数 | 类型 | 说明 |
---|---|---|
fd | int | 文件描述符 |
cmd | int | 锁操作命令: |
- F_GETLK :检测锁状态(不实际加锁) | ||
- F_SETLK :非阻塞式设置/释放锁 | ||
- F_SETLKW :阻塞式设置锁(等待锁释放) | ||
lock | struct flock* | 描述锁类型与范围的指针,结构体成员如下: |
struct flock {
short l_type; // 锁类型:F_RDLCK/F_WRLCK/F_UNLCK
short l_whence; // 基准位置:SEEK_SET/SEEK_CUR/SEEK_END
off_t l_start; // 偏移量(相对于l_whence)
off_t l_len; // 锁定字节数(0表示至文件尾)
pid_t l_pid; // 持有锁的进程ID(F_GETLK时填充)
};
2.4 返回值
• 成功:根据cmd
不同返回不同:
• F_GETLK
:非负值(锁信息存于lock
结构)
• F_SETLK
/F_SETLKW
:0
• 失败:返回-1
,常见错误:
• EACCES
/EAGAIN
:锁冲突(非阻塞模式)
• EDEADLK
:死锁风险(仅限F_SETLKW
)
• EINVAL
:无效参数
三、关键特性对比
特性 | flock | fcntl |
---|---|---|
锁粒度 | 整个文件 | 文件区域(字节级) |
锁类型 | 共享/互斥 | 共享/互斥/释放 |
阻塞控制 | 支持LOCK_NB 非阻塞 | 通过F_SETLK /F_SETLKW 区分 |
锁继承 | 子进程不继承锁 | 子进程继承锁 |
锁检测 | 需显式调用检查 | 内置锁状态查询(F_GETLK ) |
跨进程兼容性 | 与fcntl 锁互斥 | 与flock 锁互斥 |
自动放锁 | 关闭一个文件的所有文件描述符 | 关闭一个文件的任意文件描述符 |
四、应用场景建议
• 简单同步:优先使用flock
,代码简洁且适用于全文件锁定
• 高性能并发:选择fcntl
,利用区域锁减少竞争
• 强制锁需求:需结合文件系统配置(如mount -o mand
)
• 单实例daemon:在/var/run下创建“进程号.pid”文件,并持有该文件的POSIX写锁。一旦有另一个进程运行同一个程序,发现取得不了锁后就知道已经有一个实例在运行了。一般该文件先用truncate或fturncate截断为长度0,然后写入进程的pid,最后在程序结束的时候删除(remove或unlink)该文件防止占用文件系统资源。