【问题标题】:How to avoid race condition when using a lock-file to avoid two instances of a script running simultaneously?使用锁定文件避免两个脚本实例同时运行时如何避免竞争条件?
【发布时间】:2010-09-24 10:45:11
【问题描述】:

避免同一脚本的两个实例同时运行的典型方法如下所示:

[ -f ".lock" ] && exit 1
touch .lock
# do something
rm .lock

有没有更好的方法来锁定来自 shell 脚本的文件,从而避免竞争条件?必须改用目录吗?

【问题讨论】:

  • 问题应通过选择答案标记为“[已解决]”,而不是通过编辑标题并添加“[已解决]”。
  • 问题是,我无法将自己的答案标记为“已接受”
  • 坦率地说,我不认为你的答案是最好的:)

标签: linux bash shell locking mutex


【解决方案1】:

是的,示例脚本中确实存在竞争条件。您可以使用 bash 的 noclobber 选项,以便在比赛中失败,当不同的脚本潜入 -f 测试和 touch 之间时。

以下是说明机制的示例代码-sn-p(灵感来自this article):

if (set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null; 
then
   # This will cause the lock-file to be deleted in case of a
   # premature exit.
   trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

   # Critical Section: Here you'd place the code/commands you want
   # to be protected (i.e., not run in multiple processes at once).

   rm -f "$lockfile"
   trap - INT TERM EXIT
else
   echo "Failed to acquire lock-file: $lockfile." 
   echo "Held by process $(cat $lockfile)."
fi

【讨论】:

  • 如果其他人想知道$$ 做了什么,它会返回正在运行的脚本的 PID(进程 ID)。
【解决方案2】:

试试flock命令:

exec 200>"$LOCK_FILE"
flock -e -n 200 || exit 1

如果锁定文件被锁定,它将退出。它是原子的,可以在最新版本的 NFS 上运行。

我做了一个测试。我创建了一个包含 0 的计数器文件,并在两台服务器上同时执行以下循环 500 次:

#!/bin/bash

exec 200>/nfs/mount/testlock
flock -e 200

NO=`cat /nfs/mount/counter`
echo "$NO"
let NO=NO+1
echo "$NO" > /nfs/mount/counter

一个节点正在与另一个节点争夺锁。当两次运行完成时,文件内容为 1000。我尝试了多次,它总是有效!

注意:NFS 客户端是 RHEL 5.2,使用的服务器是 NetApp。

【讨论】:

  • 对羊群的覆盖率相当不错:在我的抽样中,我在 Cygwin 和 Linux 上都有它,但在 Solaris 或 Mac 上没有。
  • 您介意再解释一下语法吗?我特别想知道exec 200>"$LOCK_FILE"。将通过手册页解决这个问题,但如果它解释了这些行的作用,你的答案会更好。
  • Bash 3.2 手册,第 3.6 节:“使用大于 9 的文件描述符的重定向应谨慎使用,因为它们可能与 shell 内部使用的文件描述符冲突。”频繁使用 FD 200(例如多个进程连续 500 次)可能会导致问题,不是吗?
【解决方案3】:

锁定您的脚本(防止并行运行)

http://wiki.bash-hackers.org/howto/mutex

仅供参考。

【讨论】:

    【解决方案4】:

    创建一个目录是原子的,如果你不使用-p,如果它已经存在就会失败,所以

     mkdir $lockName || exit 1
    

    有效。

    ...但请改用flock

    【讨论】:

      【解决方案5】:

      似乎我找到了一个更简单的解决方案:man lockfile

      【讨论】:

      • 请注意,lockfile 不可移植——它可能不可用;它是 procmail (AFAIK) 的一部分。
      • shell 比 procmail 更便携,因为你更可能拥有 bash 而不是 procmail。我在这里有 Solaris、Linux、Mac 和 Windows 上的 bash。 lockfile 不在其中。
      • 我使用 noclobber 编写了一个 bash 脚本,它模仿了 Procmail 的锁定文件的一些行为。它应该是可移植的,你可以在这里找到它:codng.com/2011/05/file-locks-in-bash.html
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-12
      • 1970-01-01
      相关资源
      最近更新 更多