2

我们正在并行运行许多 jenkins 项目。我们使用的是 python,我们选择使用 pyenv 来管理虚拟环境。不幸的是,pyenv 有一个众所周知的竞争条件。为了解决这个问题,我想在进程级别实现锁定。我想做的是:

lock some resource (a file?)
do my pyenv stuff
unlock the resource

我的脚本是用 bash 编写的。如何在 bash 中实现资源锁定/解锁?

4

2 回答 2

3

因此,当您想要跨进程锁时,您在 unix 世界中的朋友是一个名为flock. 它被实现为操作系统级别的原子操作,对于这类事情非常有用。你可以在这里阅读更多关于它的信息。以下是如何使用它:

  # Wait for lock on  (fd 222) for 10 seconds
  (flock -w 10 222 || exit 1

  {
      # Do the operations you want to here
  }) 222>/path/to/lockfile 

这里有几个技巧。首先,通常在使用输出重定向时,bash 会在尝试使用群之前先打开一个文件。但是,在这里,因为我们有()bash 将首先启动一个子shell,其第一个命令是flock。flock 将尝试获取文件句柄 222 上的锁定。然后 Flock 将锁定文件描述符。锁定文件描述符后,{}运行中的代码。在运行之后,文件描述符222的内容被写入锁定文件(即,什么都没有),文件被关闭并且锁定被释放。这就像 C 中关闭文件释放锁一样。当然,没有比解释这里发生的事情的杰出@CharlesDuffy(帽子提示@codeforester)更好地解释它。

于 2016-12-22T05:01:00.283 回答
1

我会考虑使用符号链接而不是常规文件 - 因为,符号链接创建是一个原子操作。所以,我们可以这样做:

lockfile=/path/to/lock.file
# lockfile is a symlink that points the string that holds the PID of the locking process
ln -s $$ $lockfile 2>/dev/null
if [[ $? == 0 ]]; then
    # got the lock - ln -s will fail if symlink exists already
else
    otherprocess=$(readlink $lockfile)
    if [[ $otherprocess != $$ ]]; then
        ps -p $otherprocess 2>/dev/null
        if [[ $? != 0 ]]; then
            # stale lock; remove and lock again
            # this can result in race conditions
            # probably, we can make the lock procedure as a function that is shared by concurrent bash scripts and have a random sleep before we remove the stale lock and proceed
         fi
    fi
fi
于 2016-12-22T04:46:51.877 回答