bash 中有效建立锁

有时候需要防止一段代码在被同时执行,就需要使用锁来防止代码重入。常常见到这样的代码:

if [ -f /var/lock/mylock ]; then
  touch /var/lock/mylock
  ...
  rm -f /var/lock/mylock
fi

但实际上,这样是有问题的。如果两个进程在 test ( [ ) 和 touch 之间,另一个进程同时执行,就会出现竞争问题,最后就可能出现同时运行的情况。要避免这种情况出现,就得改一下加锁的方式。可以用 mkdir 代替 touch,这样在锁目录以及存在的时候,会直接出错;

if mkdir /var/lock/mylock 2>/dev/null; then
  ...
  rm -rf /var/lock/mylock
fi

或者先用 set -C ,让 > 重定向在文件已经存在时出错,然后用 echo … > 来生成锁文件

if ( set -C; echo $$> /var/lock/mylock 2>/dev/null); then
  ...
  rm -f /var/lock/mylock
fi

这两种方法可以保证加锁和检测锁是一个原子操作,避免竞争问题。

坑爹的 phpunit

最新的 phpunit 是 3.6 。之前用的是 3.5 。在一个新机器上安装,按官网的方法,装了新版本后,运行,出错!

Call to undefined method PHP_CodeCoverage_Filter::getInstance()

新版本的 CodeCoverage 改变了调用方法。从 phpunit 3.4 升级到 3.5 的时候,CodeCoverage 的使用也发生过改变。这回又来了…… 这次不想改测试代码,于是打算用旧的 PHP_CodeCoverage 。于是

sudo pear install -f http://pear.phpunit.de/get/PHP_CodeCoverage-1.0.5.tgz

结果,还是出错

Class ‘File_Iterator’ not found

看看 pear 的目录里,明明有 File/Iterator.php 啊,再看看那个 Iterator/Factory.php ,里面没有 require。。。 试着加一条

require_once 'File/Iterator.php';

这回 ok 了。不过改代码这事也挺恶心。于是试着把 File_Iterator 也用个旧版本

sudo pear install -f http://pear.phpunit.de/get/File_Iterator-1.2.6.tgz

然后就又 ok 了。

这货为啥总是改接口呢?还不保持向后兼容呢……