文件系统技术内幕:大数据时代海量数据存储之道
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.6.2 Linux文件锁的使用

在Linux中,文件锁的特性是通过flock()和fcntl()两个函数对外提供的。这两个函数都可以实现文件加锁和解锁的流程,但是后者要比前者的特性更加丰富。

2.6.2.1 flock()函数的使用简析

下面先介绍一下flock API的使用,flock()函数的语法格式如下:

可以看出,该函数有两个参数,一个是文件的句柄,另一个是具体的动作。flock()函数行为的差异依赖于operation参数,该参数可以是如下几种情况。

• LOCK_SH:表示加共享锁(Shared Lock)。

• LOCK_EX:表示加排他锁(Exclusive Lock)。

• LOCK_UN:表示释放锁(Unlock)。

可以看出,文件锁的加锁和解锁都是由flock()函数实现的。在了解了上述参数的含义之后,再使用该函数就不太难了,此处就不再举例说明。

2.6.2.2 fcntl()函数的使用简析

fcntl()函数实现的特性要更加丰富一些,它不仅可以用于锁操作,还可以用于其他操作,这主要依赖参数cmd的值。fcntl()函数的语法格式如下:

可以看出,该函数有两个主要的参数,一个是fd,表示目标文件描述符;另一个是cmd,用于确定具体的操作,对于文件锁cmd来说,可以是F_GETLK、F_SETLK和F_SETLKW。其实后面还有第3个参数,这个参数是可变参数。对于文件锁操作,第3个参数的类型为struct flock。此时函数的语法格式如下:

lock参数是文件锁的详细属性信息,它描述了我们想要添加什么类型的文件锁,以及其他一些描述信息。该结构体包含的内容如代码2-7所示。

代码2-7 文件锁结构体

通过上述参数可以看出,该方法不仅可以实现各种文件锁类型,文件锁的粒度也会更细一些。其中,成员l_start与l_len用于描述锁定的文件的范围。

成员l_type描述了文件锁操作的具体类型,它的值可以是F_RDLCK、F_WRLCK和F_UNLCK等。其中,F_RDLCK是加读(共享)锁,F_WRLCK是写(排他)锁,而F_UNLCK是解锁操作。当对文件进行加锁或解锁操作时,只需要填充相应的参数,并调用该接口即可。

为了更加清楚地说明上述各个参数的用途,下面列举一个实例。在该实例中定义了一个排他锁。同时,通过F_SETLKW参数让fcntl()函数添加一个需要等待(Wait)模式的锁(第30行),如代码2-8所示。

代码2-8 文件锁使用实例

编译并执行上述代码,然后开启另一个窗口再次执行上述代码。我们会发现该程序被阻塞了。如果将第30行代码中的F_SETLKW修改为F_SETLK,此时程序并不会被阻塞,而是会返回一个错误。

如果这时使用其他软件访问该文件,会出现什么结果呢?比如,使用cat命令读取文件数据。

结果是可以正常读取数据。这时大家可能会产生疑问。加锁不是实现对数据的排他保护吗?怎么还可以读取数据呢?这是因为在Linux中默认使用的是劝告锁。如果进程没有对锁的状态进行询问而直接访问数据,则锁并不会保护数据。

为了对某个特定文件施行强制性上锁,需要使用强制锁。使用强制锁需要满足如下几个条件。

(1)挂载文件系统时要指定mand选项(mount-o mand)。

(2)必须关闭文件的组成员执行位(chmod g-x file)。

(3)必须打开文件的SGID位(chmod g+s file)。这里SGID(Set Group ID)是文件/目录的一种特殊权限,用于用户临时获得组权限。

完成上述操作后,如果在第1个窗口运行该程序,则在第2个窗口执行cat命令或vim命令查看文件数据时会被阻塞。