2013-06-09

UNIX風OSで同じプログラムの複数起動を防ぐ方法

若い頃、OSに不自由なWindowsを選んでしまったがばっかりに、今GNU/Linuxに移って、UNIXの流儀を飲み込むのに苦労している。

さて、UNIX風OSで、同じプログラムの複数起動を防ぐ方法は、一体どうやって実装すればいいのか。

クローズドソースのWindowsならば、ある決められた名前付きのカーネルオブジェクトを作成すればよい。カーネルオブジェクトはいくつも種類があるが、なんだっていい。カーネルオブジェクトの作成はアトミックに行われる。すでに同じ名前のカーネルオブジェクトが存在する場合、その情報も伝えられる。これにより、すでにカーネルオブジェクトが作成されたかどうかがわかり、重複起動も判断できる。プロプライエタリなWindowsのカーネルオブジェクトはリファレンスカウントされており、参照するプロセスが存在しなくなった時点で破棄される。そのため、プロセスがクラッシュしたり外から強制的に終了させられた場合にも、安全である。

Linuxカーネルにも、ユーザースペース向けのカーネルオブジェクトはあるのだが、どうもmanページを読む限り、参照カウントは行われていないようだ。これでは異常終了した場合の備えができない。

追記:Linuxカーネルの名前付きセマフォは、プロセスの終了時やexecve時に自動的に閉じられるとあるので、この目的に使える。
追記2:とおもったが、やはり使えないようだ。

かわりにいくつもあるテクニックは、どれもファイルを利用したもののようだ。

pidfile

これは、OSの提供するファイル作成の機能を利用する。ある決められた名前のファイルを、ある決められたディレクトリ下(システムで重複確認ならば/var/runあたりに、ユーザーごとに重複確認ならばホームディレクトリに)に作成する。そして、自分のプロセスのpidを書き込む。終了時にファイルを削除するという方法だ。

もし、プロセスの起動時に存在し、現在有効で、しかも自分と同じプログラムから起動されたpidが書き込まれていた場合、すでに他のプロセスが起動している。

ファイルが存在しない場合、ファイルが存在するが、pidが現在無効な場合や自分のプログラムとは違う場合、重複していない。

問題は、これはどうも、ファイルの作成や書き込みがアトミックに行われることを前提にしているようだ。果たして今でも通用するのだろうか。

ファイルロック

これはOSの提供するファイルにロックをかける機能を利用する。ファイルロックには、既存のファイルにロックをかける機能と、作成からアトミックに行う機能があるが、とにかくファイルロックを使う。

問題は、この方法は余り使われていない。というのも、どうもUNIX風OSでは、伝統的にファイルロックの実装の質が悪いようなのだ。実装されていないとか、実装されているがAPIがバラバラとか、実装はされているがまともに動かないとか、あるファイルシステムでは動かないとか、ランダムに動かないとか、とにかく移植性が悪く、信頼できないらしい。

ディレクトリ作成

これはOSの提供するディレクトリ作成を機能を利用するもの。ほとんどの環境で、ディレクトリの作成はアトミックに行われるらしく、お手軽で移植性も高いのだとか。ただし、プロセスが異常終了した場合を考慮して、pidfileとの併用を行う。

方法はいろいろあるが、どうも原始的な感じがするのは、まだUNIXの流儀に十分に慣れ親しんでいないせいだろうか。

1 comment:

fumiyas said...

PID ファイルの作成ですが、ファイル作成の競合は避ける方法があります。open(2) の O_EXCL フラグを参照。

ファイルのロックですが、NFS とか共有ファイルシシテムを利用していないなら、通常は問題ありません。NFS でもちゃんと設定して flock(2) でなく fcntl(2) のロックなら問題なし。ただ Windows と違って UNIX 系 OS のロックはアドバイザリーロックなので、ロックを見ないプログラムで無視できます。Windows と同じ強制ロックも可能ですが、一般的ではないです。
http://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%AD%E3%83%83%E3%82%AF