従来、ファイルの排他制御であれば、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