flock(1) というコマンドがあります。flock(2) を使い、コマンドを排他制御して実行します。

$ flock /path/to/lockfile command...

これで lockfile をロックファイルとしてコマンドを排他制御実行します。

これが「普通の」使い方なわけですが、もう1つ、 Linux だとファイルディスクリプタ番号を指定する使い方があります(Linux 以外で使えるかどうかは調べてない)

#!/bin/sh
(
   flock 100
   command...
) 100>>/path/to/lockfile

これも lockfile を ロックファイルとして後続のコマンド群(丸かっこで囲った部分)を排他制御実行します。実際には

#!/bin/sh
exec {LOCKFD}>>/path/to/lockfile
flock $LOCKFD
command...

などとして空いているファイルディスクリプタ番号をカーネルに選ばせる方が安全ですが。

ともあれ、こっちの方が柔軟性がある(たとえばスクリプトの途中でアンロックすることもできる)わけですが、これ flock はロックに成功したらすぐ返ってくる(そうでないと後続のコマンドが実行できない)わけで、なんでそれで排他制御できているのか5分ほど悩みました。

なんで排他制御できるのかというと、

  • flock を実行する際、ファイルディスクリプタテーブルはコピーされる。上記のスクリプトで言う 100 番は恐らく close on exec フラグは立ってないので、子プロセスである flock にも継承される。
  • flock が 100 番をロックする。この時、ロックはファイルディスクリプタ番号自体ではなく、ファイルディスクリプタが指すカーネル内の構造に対してかかるため、親プロセスとロック所有権を共有している形になる。
  • flock が終了し、親プロセス(だけ)がロックを持っている状態になる。

という原理です。

しかし最近シェルスクリプト書いてないな(ワンライナーならそれなりに書いてるけど)。

Trackback

no comment untill now

Add your comment now