关于Atomic可以参考 Atomic Operation and Atomic Command
lockfile
flock
mkdir
ln -s
需要注意的是,有些命令对于NFS(Network File System),是无效的。根据StackOverflow上的一个说法:
symlink
和 rename
create
mkdir
因此,利用文件进行lock/unlock可以如下操作:
# lock while ! ln -s ${f} ${f}.lock; do :; done # unlock mv ${f}.lock ${f}.unlock && rm ${f}.unlock
有时需要一个程序只有一个正在运行的实例。
来自StackOverflow上的一个方法:
LOCKFILE=/tmp/lock.txt if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then # TODO: what if another instance just start here echo "already running" exit fi # make sure the lockfile is removed when we exit and then claim it trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT echo $$ > ${LOCKFILE} # do stuff sleep 1000 rm -f ${LOCKFILE}
其中的trap
语句用于"unlock"操作——清除lock文件。
这个方法的缺点是:如果另外一个进程恰好在检查之后启动。(代码中标记"TODO"的地方。虽然这是小概率事件)
潜在的问题的主要原因是检查文件存在和创建文件之间有时间间隔,不是一个atomic操作。
为了解决这个问题,可以借助mkdir
命令。需要注意的是这个命令对于NFS可能是无效的。
一段Shell程序产生的代码是否是atomic呢?
比如下面的代码借助Bash的noclobber
来实现lock检测。
set -C lockfile="/tmp/locktest.lock" if echo "$$" > "$lockfile"; then echo "Successfully acquired lock" # do work rm "$lockfile" # XXX or via trap - see below else echo "Cannot acquire lock - already locked by $(cat "$lockfile")" fi
可以借助strace
命令来测试:
$ strace -e trace=creat,open -f /bin/bash testlock 2>&1 | grep -F test.lock open("/tmp/testopen.lock", O_WRONLY|O_CREAT|O_EXCL|O_LARGEFILE, 0666) = 3
下面是一个更为简化的用法示例:
if (set -C; >$lockfile); then ...