如何避免bash脚本中的竞争条件?

时间:2015-02-18 03:53:04

标签: bash race-condition

#!/bin/bash
if [ ! -f numbers ]; then echo 0 > numbers; fi
count=0
touch numbers
echo $count > numbers
while [[ $count != 100 ]]; do
  if ln numbers numbers.lock
  then
    count=`expr $count + 1`
    n=`tail -1 numbers`
    expr $n + 1 >> numbers
    rm numbers.lock
  fi
done

我可以做些什么来避免count=`expr $count + 1`n=`tail -1 numbers`的竞争条件,这样当我同时运行两个脚本时,它只会变为100,而不是200。我在多个网站上进行了研究,但没有一个庞大的功能,没有简明的答案。

1 个答案:

答案 0 :(得分:3)

您已经使用锁定文件安全地避开了实际的竞争条件。您所描述的问题可以通过两种方式避免。

(1)将锁定文件移到主循环之外,这样程序的两个实例就不能同时运行它们的主循环。如果一个正在运行,另一个必须等​​到它完成,然后开始替换输出文件。

#!/bin/bash
while true; do
    if ! ln numbers numbers.lock
    then
       sleep 1
    else
        if [ ! -f numbers ]; then echo 0 > numbers; fi
        count=0
        touch numbers
        #echo $count > numbers   # needless, isn't it?
        while [[ $count != 100 ]]; do
            count=`expr $count + 1`
            n=`tail -1 numbers`
            expr $n + 1 >> numbers
            rm numbers.lock
        done
        break
    fi
done

(2)通过检查文件的内容,使两个实例合作。换句话说,强制它们在数字达到100时停止循环,而不管有多少其他进程正在写入此文件。 (我猜当有超过100个实例在运行时会出现一个iffy的情况。)

#!/bin/bash
# FIXME: should properly lock here, too
if [ ! -f numbers ]; then echo 0 > numbers; fi
n=0
touch numbers
while [[ $n -lt 100 ]]; do
  if ln numbers numbers.lock
  then
    n=$(expr $(tail -1 numbers) + 1 | tee numbers)
    rm numbers.lock
  fi
done

根据您的要求,您可能希望脚本在脚本的新实例启动时破坏文件中的任何先前值,但如果不是,则echo 0 > numbers应由锁定文件管理,太