2013年8月19日,兰德尔·施瓦茨发布了这 shell脚本,目的是确保在Linux上“只运行一个脚本实例,而不存在竞争条件,也不需要清理锁文件”:
#!/bin/sh
# randal_l_schwartz_001.sh
(
if ! flock -n -x 0
then
echo "$ cannot get flock"
exit 0
fi
echo "$ start"
sleep 10 # for testing. put the real task here
echo "$ end"
) < $0它似乎如宣传的那样起作用:
$ ./randal_l_schwartz_001.sh & ./randal_l_schwartz_001.sh
[1] 11863
11863 start
11864 cannot get flock
$ 11863 end
[1]+ Done ./randal_l_schwartz_001.sh
$以下是我所理解的:
<)重定向到子subshell的STDIN (即文件描述符0)。0上的非阻塞独占锁(D12)。以下是我的问题:
0的独占锁会阻止运行在不同shell中的同一个脚本的副本获得文件描述符0上的独占锁?shells是否有自己的标准文件描述符(0、1和2,即STDIN、STDOUT和STDERR)的独立副本?发布于 2019-01-03 21:05:28
通过文件描述将文件锁附加到文件。在较高级别上,脚本的一个实例中的操作顺序是:
保持锁可以防止同一脚本的另一个副本运行,因为锁就是这样做的。
打开一个文件会创建一个文件描述。这是一个内核对象,在编程接口中没有太多的可见性。锁是文件描述的属性之一,而不是文件或描述符的属性。
在打开文件时,文件描述只有一个文件描述符,但可以通过创建另一个描述符( dup系列系统调用)或分叉子进程(其父进程和子进程都可以访问相同的文件描述)来创建更多的描述符。文件描述符可以显式关闭,也可以在进程退出时关闭。当附加到文件的最后一个文件描述符关闭时,文件描述将关闭。
下面是上面操作的顺序对文件描述的影响。
<$0在子subshell中打开脚本文件,创建文件描述。此时,有一个文件描述符附加到描述:子subshell中的描述符号0。flock并等待它退出。当flock正在运行时,在描述中附加了两个描述符:子subshell中的数字0和flock进程中的数字0。当flock获得锁时,它将设置文件描述的属性。如果另一个文件描述已经在该文件上有一个锁,flock不能接受该锁,因为它是一个独占锁。脚本使用来自$0的重定向的原因是,重定向是在shell中打开文件的唯一方法,而保持重定向活动是保持文件描述符打开的唯一方法。子subshell从不从它的标准输入中读取,它只需要打开它。在允许直接访问打开和关闭调用的语言中,可以使用
fd = open($0)
flock(fd, LOCK_EX)
do stuff
close(fd)如果使用exec内置的重定向,实际上可以在shell中获得相同的操作序列。
exec <$0
flock -n -x 0
# do stuff
exec <&-如果脚本想继续访问原始的标准输入,它可以使用不同的文件描述符。
exec 3<$0
flock -n -x 0
# do stuff
exec 3<&-或者有一个子壳:
(
flock -n -x 3
# do stuff
) 3<$0锁不一定在脚本文件上。它可以在任何可以打开以读取的文件上(因此它必须存在,它必须是可以读取的文件类型,例如常规文件或命名管道,而不是目录,并且脚本进程必须具有读取它的权限)。脚本文件的优点是它保证了它的存在和可读性(除了在调用脚本和脚本到达<$0重定向之间外部被删除的边缘情况下)。
只要flock成功,并且脚本位于锁没有错误的文件系统上(一些网络文件系统,如NFS可能有buggy),我就不知道如何使用不同的锁文件来允许争用条件。我怀疑你的操纵错误。
发布于 2019-01-03 20:49:21
用于锁定的文件并不重要,脚本使用$0,因为这是一个已知存在的文件。
获得锁的顺序或多或少是随机的,这取决于机器启动这两个任务的速度。
您可以使用任何文件描述符,而不一定是0。锁被保存在打开给文件描述符的文件上,而不是描述符本身。
( flock -x 9 || exit 1
echo 'Locking for 5 secs'; sleep 5; echo 'Done' ) 9>/tmp/lock &https://unix.stackexchange.com/questions/492324
复制相似问题