`flock -u` 到底做了什么?

What does `flock -u` actually do?

我正在使用命令 flock,它获取和释放对文件的锁定。例如,如果我 运行

flock /tmp/mylock true

然后它立即退出,大概是获取然后释放锁。如果我运行

flock /tmp/mylock sleep 100

然后延迟100秒,再次获取和释放锁。而且,如果我 运行 以下两个单独的 shells:

flock /tmp/mylock sleep 100

flock /tmp/mylock true

那么第二个命令就被阻塞了,因为它在第一个命令运行s的时候无法获取到锁。一旦 sleep 100 完成并释放锁,第二个命令 运行s 并退出。一切顺利。

问题来了。如果在这 100 秒的延迟期间,我 运行 在第三个 shell 中执行以下操作:

flock -u /tmp/mylock true

然后会发生什么? flock 的手册页说:

   -u, --unlock
          Drop  a  lock.   This  is  usually not required, since a lock is
          automatically dropped when the file is closed.  However, it  may
          be  required  in special cases, for example if the enclosed com-
          mand group may have forked a background process which should not
          be holding the lock.

所以,这应该放下锁,这应该允许 flock /tmp/mylock true 到 运行,对吧? (我也猜测 flock /tmp/mylock sleep 100 会立即退出,但这是推测。)

会发生什么?没有什么。 flock -u /tmp/mylock true立即退出,但flock /tmp/mylock true继续阻塞,flock /tmp/mylock sleep 100继续退出。

flock -u /tmp/mylock <command>实际上是做什么的?

(所有示例均在 Ubuntu 18.04 上测试。)

这是一个示例,其中 -u 使用在文件 mylock 上打开的文件描述符 9,成功解锁 9,以便后台 flock mylock 可以继续。 请注意,flock 9 也不能有命令,因为在这种情况下,“9”被视为文件名,而不是 fd。

bash -s <<\!  9>mylock 2>&1 |
 flock 9; echo gotlock1
 flock 9; echo gotlock2
 9>&- flock mylock bash -c 'echo start_sleep;sleep 8; echo end_sleep' &  
 sleep 2
 flock -u 9; echo unlock; sleep .1
 flock 9; echo gotlock3
!

awk '{t2=systime(); if(t1==0)t1=t2; printf "%2d %s\n",t2-t1,[=10=]; t1=t2}'

第一行使 bash 运行 在打开 fd 9 之后成为以下几行,而且还通过最后看到的 awk 脚本通过管道传输 stdout 和 stderr。这只是用行的时间来注释输出。结果是:

 0 gotlock1
 0 gotlock2
 2 unlock
 0 start_sleep
 8 end_sleep
 0 gotlock3

这会立即显示前 2 个 flock 9 命令 运行。然后一个 flock mylock 命令在后台是 运行,在关闭 fd 9 之后只是为了这一行。例如,此命令可能是来自第二个 window 的 运行。输出显示它挂起,因为我们没有看到 start_sleep。这意味着前面的 flock 9 确实获得了独占锁。

然后输出显示在 sleep 2flock -u 9 之后我们得到 unlock 回显,然后后台命令才获得锁并启动它的 sleep 8 .

主脚本立即执行flock 9,但输出显示直到后台脚本以end_sleep 8 秒后结束,主脚本输出gotlock3.

lslocks 命令有时会显示 2 个对锁感兴趣的进程。 * 表示等待:

COMMAND           PID  TYPE SIZE MODE  M      START        END PATH
flock           23671 FLOCK   0B WRITE* 0          0          0 /tmp/mylock
flock           23655 FLOCK   0B WRITE  0          0          0 /tmp/mylock

但是它本身并没有显示第一个 flock 9 的结果,大概是因为没有进程拥有锁,即使文件确实被锁定了,正如我们看到的后台作业无法继续。