従来、ファイルの排他制御であれば、mkdir(),symlink()等を利用してビジー ウェイトさせる手法であったり、flock(),lockf(),fcntl()等を駆使して排他 制御を行ったりしていました。またファイル以外のリソースを排他制御する場 合は、セマフォ等を使って制御していたと思います。これらの排他制御の質は 個々のプログラマの力量に左右されたり、プログラム個々にコーディングされ ることにより、システム全体として統一した制御はなかなか難しく、仮に優秀 なプログラマが綿密に設計したとしても、デッドロック等の不可避な問題が常 に付きまとっていました。
grmdはクライアントサーバ方式で制御を行い、あらゆるリソースの排他制御を 共通のインタフェースで行うことができます。特徴としては、
$ tar xvzf grmd-0.3.tar.gz $ cd grmd-0.3 $ vi Makefile $ make $ su # make install # vi /usr/local/grmd/keystring # 管理者用キー文字列設定(最大256文字) # vi /etc/hosts.allow # vi /etc/hosts.deny(*) BSD系OSの場合、カーネルのSYSVMSGオプションが有効になっていることを 確認して下さい。
# /usr/local/grmd/rc.grmd
$ /usr/local/grmd/rc.grmd -h usage : rc.grmd [-d|--dir home_directory] [-H|--host hostname] [-p|--port port] [-q|--queue queue_count] [-k|--key keystring_file] [-l|--log logfile] [-f|--foreground] -d|--dir home_directory ... home directory. [/usr/local/grmd] -H|--host hostname ... hostname which daemon run in. [localhost] -p|--port port ... socket port which client talk to. [20100] -q|--queue queue_count ... queue count of socket backlog. [128] -k|--key keystring_file ... file (in home_directory) which administrator keystring is written in. [keystring] -l|--log logfile ... file (in home_directory) which daemon record messages to. [logfile] -f|--foreground ... run in foreground [none]
表1 | ||
SHARE_LOCK(1) | EXCLUSIVE_LOCK(1) | |
SHARE_LOCK(2) | 排他獲得 | 解放待ち |
EXCLUSIVE_LOCK(2) | 解放待ち | 解放待ち |
GET LOCK +---------------->(Process 1) | | | [Resource 1] [Resource 2] (Process 2) (図1)
GET LOCK +---------------->(Process 1) | | | [Resource 1] [Resource 2] | | | (Process 2)<----------------+ GET LOCK (図2)
GET LOCK WAIT LOCK +---------------->(Process 1).................+ | : | : | v [Resource 1] [Resource 2] | | | (Process 2)<----------------+ GET LOCK (図3)
GET LOCK WAIT LOCK +---------------->(Process 1).................+ | : | : | v [Resource 1] [Resource 2] X | : | : | +.................(Process 2)<----------------+ DEADLOCK!! GET LOCK (図4)
lock pid resid lockmode keystring 機能 : 排他を獲得する。対象のリソースが既に他のプロセスで排他獲得 されていた場合は、解放されるまで待機する。 pid : 自己のプロセスを特定する文字列(最大256文字)。 resid : 排他の対象リソースを特定する文字列(最大256文字)。 lockmode : 排他制御モードを指定する文字列。 share_lock, sl, s exclusive_lock, el, x keystring : 対象リソースをunlockする際に指定するキー文字列(最大256文字)。 戻値 : OK : 排他獲得成功 DEADLOCK : 排他獲得失敗(デッドロック検知) NG : 排他獲得失敗
unlock pid resid keystring 機能 : 排他を解放する。開放を待っていたプロセスを起こす。 pid : 自己のプロセスを特定する文字列(最大256文字)。 resid : 排他の対象リソースを特定する文字列(最大256文字)。 keystring : 対象リソースをlockする際に指定したキー文字列(最大256文字)。 戻値 : OK : 排他解放成功 NG : 排他解放失敗
spr keystring 機能 : リソースの状態をログファイルに書き出す(pid-resid)。 keystring : デーモン起動時に指定した管理者用キー文字列(最大256文字)。 戻値 : OK : 成功 NG : 失敗
srp keystring 機能 : リソースの状態をログファイルに書き出す(resid-pid)。 keystring : デーモン起動時に指定した管理者用キー文字列(最大256文字)。 戻値 : OK : 成功 NG : 失敗
getpr keystring 機能 : リソースの状態を取得する(pid-resid)。 keystring : デーモン起動時に指定した管理者用キー文字列(最大256文字)。 戻値 : OK pid resid status keystr : 成功 NG : 失敗
getrp keystring 機能 : リソースの状態を取得する(resid-pid)。 keystring : デーモン起動時に指定した管理者用キー文字列(最大256文字)。 戻値 : OK resid pid status keystr : 成功 NG : 失敗
機能:排他開始 引数:host, port, pid, resid, lockmode, keystring 戻値:status 例 :$status = grm_lock("localhost", "20100", "process1", "resource1", "SHARE_LOCK", "Gehime"); lockmode : SHARE_LOCK, SL, S EXCLUSIVE_LOCK, EL, X
機能:排他終了 引数:host, port, pid, resid, keystring 戻値:status 例 :$status = grm_unlock("localhost", "20100", "process1", "resource1", "Gehime");
機能:リソース状態表示(pid-resid) 引数:host, port, keystring 戻値:status 例 :$status = grm_spr("localhost", "20100", "Gehime");
機能:リソース状態表示(resid-pid) 引数:host, port, keystring 戻値:status 例 :$status = grm_srp("localhost", "20100", "Gehime");
機能:リソース状態取得(pid-resid) 引数:host, port, keystring 戻値:status pid resid status keystr 例 :$responce = grm_getpr("localhost", "20100", "Gehime"); @stat_pid_resid_status_keystr = split(/\n/, $responce); foreach $i (@stat_pid_resid_status_keystr){ ($stat, $pid, $resid, $status, $keystr) = split(/\t/, $i); }
機能:リソース状態取得(resid-pid) 引数:host, port, keystring 戻値:status resid pid status keystr 例 :$responce = grm_getrp("localhost", "20100", "Gehime"); @stat_resid_pid_status_keystr = split(/\n/, $responce); foreach $i (@stat_resid_pid_status_keystr){ ($stat, $resid, $pid, $status, $keystr) = split(/\t/, $i); }
# sample1.plはプロセス`p1'として、リソース`r1.txt'、`r2.txt'の # 順に確保し、データに1加算を100回行う。 # # sample2.plはプロセス`p2'として、リソース`r2.txt'、`r1.txt'の # 順に確保し、データに1加算を100回行う。 # # sample3.plはプロセス`p2'として、リソース`r1.txt'、`r2.txt'の # 順に確保し、データに1加算を100回行う。 # # デッドロックを起こすパターン # $ ./sample1 localhost 20100 & ./sample2 localhost 20100 # # デッドロックを起こさないパターン # $ ./sample1 localhost 20100 & ./sample3 localhost 20100
$ ./grmd_sweep.pl localhost 20100