本文博客链接:https://zohead.com/archives/linux-fcntl-advisory-mandatory-lock/ 近日小温下APUE,发现Linux下的 fcntl 实现强制锁的功能好像都没试验过,简单做个测试。 首先用 fcntl 实现建议锁(Advisory locking),比较简单,贴个最简单的代码: 关键的几句已高亮显示,用 F_SETLKW 等待写的锁,很好测试,分别开一个终端运行一次就可以测试出来。 备注: Linux 同时实现了 POSIX 的 fcntl 锁函数,BSD 的 flock 函数,SVR4 的 lockf 函数,这些默认都是建议锁。 这个简单的实现只是建议锁,需要每个对文件的操作的进程都遵循同样的锁操作才能起作用,这些进程称为合作进程(Cooperative processes),但实际使用时会有例外的情况,如果另外开一个终端窗口直接写 test.file 文件,会发现可以直接写,因为这种写没有锁操作,不是合作进程,这种情况就需要用强制锁(Mandatory locking)了。 强制锁的实际代码和上面的完全一样,不过在 Linux 上需要做一些改动: 1、挂载文件系统时需要加 mand 参数在文件系统上启用强制锁支持,比较新的 Linux kernel 里已经基本在所有文件系统上都实现了; 2、去掉程序的组执行权限; 3、增加程序的设置组ID权限。 第二项和第三项在普通情况下实际上是自相矛盾的,所以 Linux 就用这种特殊情况就表示启用强制锁(Mandatory locking)了。 备注: 1、使用 BSD 的 flock 函数时不能使用强制锁,见 Linux kernel 源码下 mandatory-locking.txt 中的说明: Mandatory locks can only be applied via the fcntl()/lockf() locking interface - in other words the System V/POSIX interface. BSD style locks using flock() never result in a mandatory lock. 2、如果一个文件被某进程强制锁住,另一个进程通过 creat 函数或者 open 时加 O_TRUNC 参数,都会导致函数调用失败; 3、强制锁在不同的 UNIX 及 类UNIX 系统中实现不同,第二个备注中的 O_TRUNC 参数便是 Linux kernel 和 HP-UX 不同的地方; 4、tmpfs、nfs 也支持强制锁,可以用这两个文件系统方便测试; 5、删除文件(unlink操作)再重新创建文件,会导致强制锁失效; 6、Linux kernel 的强制锁的实现并不完全可靠(感觉白写了,哈哈,实际情况还要做处理),见 man fcntl 的说明。 强制锁的实际操作: mount -t tmpfs -o size=10m,mand tmpfs /mnt cp test /mnt cd /mnt chmod g-x test chmod g+s test 运行 test 程序,同时开另一个终端,直接用 echo 读写 test 文件,会发现强制锁已经起作用。