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