在实际应用中,经常会遇到多个程序同时操作一个文件的情况,专业术语为:文件共享,有时也称为竞态。 Linux
中通常采用的方式是对文件上锁,以解决对共享资源的竞争。
文件锁包括建议性锁和强制性锁。建议性锁要求每个相关程序在访问文件之前检查是否有锁存在,并且尊重已有的锁。而强制性锁是由内核执行的锁,当程序对文件上锁并执行写入操作时,内核将阻止其他程序对该文件进行读写操作。采用强制性锁对性能的影响较大,每次读写操作内核都检查是否有锁存在。
在 Linux
中,实现文件上锁的函数有 lockf()
和 fcntl()
,其中 lockf()
函数用于对文件施加建议性锁,而 fcntl()
函数不仅可以施加建议性锁,还可以施加强制性锁。同时, fcntl()
函数还能对文件的某一记录上锁,也就是记录锁。
记录锁又可以分为读取锁和写入锁,其中读取锁又称为共享锁,多个同时执行的程序允许在文件的同一部分建立读取锁。而写入锁又称为排斥锁,在任何时刻只能有一个程序在文件的某个部分建立写入锁。显然,在文件的同一部分不能同时建立读取锁和写入锁。
fcntl()
函数具有丰富的功能,它可以对已打开的文件进行各种操作,不仅能够管理文件锁,还可以获取和设置文件相关标志位,以及复制文件描述符等。
语法如下:
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, .../* arg */);点击复制复制失败已复制
参数 fd
为文件描述符,参数 cmd
用来实现函数不同的功能。 cmd
功能设置如下所示:
cmd |
功能 |
F_DUPFD |
复制一个现存的描述符 |
F_GETFD 或 F_SETFD |
获取或设置文件描述符标记 |
F_GETFL 或 F_SETFL |
获得或设置文件状态标志 |
F_GETOWN 或 F_SETOWN |
获得或设置异步I/O所有权 |
F_GETLK 、 F_SETLK 或 `F_SETLKW |
` 获得或设置记录锁 |
其中, F_GETFL
和 F_SETFL
用来获取或设置文件状态标志,即文件的打开和关闭中提到的 O_APPEND
、 O_NONBLOCK
等标志位。如需设置,将值传入第三个参数。
F_GETOWN
与 F_SETOWN
用来获取或设置接受 SIGIO
和 SIGURG
信号的进程ID或组ID。
如果 cmd
和锁操作有关,则第三个参数的类型为 struct flock*
,其定义如下:
struct flock { …… short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Starting offset for lock */ off_t l_len; /* Number of bytes to lock */ pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */ }点击复制复制失败已复制
flock
结构体成员如下所示:
成员 | 含义 |
l_type |
F_RDLCK :读取锁(共享锁) |
F_WRLCK :写入锁(排斥锁) |
|
F_UNLCK :解锁 |
|
l_start |
加锁区域在文件中的相对偏移量(字节),与l_whence 值一起决定加锁区域的起始位置 |
l_whence |
SEEK_SET :加锁区域为文件的开始处 |
SEEK_CUR :加锁区域为文件的当前位置 |
|
SEEK_END :加锁区域为文件的末尾处 |
|
l_len |
加锁区域的长度 |
l_pid |
具有阻塞当前进程的锁,其持有的进程的进程号存放在l_pid 中,仅由F_GETLK 返回 |