System V IPCのセマフォ・共有メモリの使い方

最近直接使わないので、(マニュアルを斜めに読んだだけではわかりにくい部分について)憶えているうちにメモ。
セマフォ
semgetで作成。第1引数の"key"は、ftokでファイル名(パス)から作成するのじゃ、とか書いてあることがあるが、気にせずIPC_PRIVATE定数を渡している。こうすると、新しいセマフォを作ってくれる。(ftokを使うのは、完全に独立して動作するプロセス間で、同じセマフォを使いたい時などに使うのであろう。)

返値がセマフォのidになる。このidのスコープはシステム全体で、異なるプロセスでも同じidのセマフォは同じセマフォを指す。したがって、全く無関係のプロセスが、同じidを使うとそのセマフォにアクセスできてしまう。セキュリティ的には、ファイルと同様のパーミッションをsemgetの第3引数に指定できるので、他人のプロセスがいたずらすることは防げる。

現在のセマフォの状況はipcsコマンドで調べることができる。ipcrmコマンドで削除することもできる。これは共有メモリも同様。

セマフォの値はsemctlで設定する。セマフォの削除もsemctlでできる。

セマフォのロック・アンロックなどはsemopで行うがこの仕様がちょっとややこしい。操作を指定する構造体のsem_opが0の場合と、正の場合と、負の場合で、それぞれ意味が異なる。

  • 0の場合は、値が0になるまで待つ。
  • 正の場合は、セマフォの値を指定された値増加させる。停止しない。
  • 負の場合は、セマフォの値が指定された値の絶対値以上になるまで停止する。通過するときに、セマフォの値を減算する。

正負の場合は、計数セマフォに使える。すなわち、リソースの量をセマフォの値で管理できる。0の場合は、ロック(バイナリセマフォ)に使う(正負だけでできそうな気もするが…)。

また、System V IPCのセマフォは、シグナルを受け取ると、停止中でもsemopから帰ってくる(Ctrl-Zを押してSIGSTOPを受け取っても抜けるので注意)。PARDSではタイムアウトつきセマフォをこれを使って実現している。

この他に、「調整値」というものがsemopに指定できて、これにより、プロセスが終了した際セマフォの値を変更できる(ロックしたままプロセスが異常終了した時に自動的にアンロックするため。多分)。現状PARDSでは使っていない。

共有メモリ:
shmgetでシステムに要求。第1引数はshmgetと同じ"key"だが、気にせずIPC_PRIVATEを指定。返り値は共有メモリのidで、このままではまだ使えない。idを使って、shmatでメモリ空間にマップする。(セマフォと同様、複数のプロセスで同じidを使うと、同じ共有メモリを指す。)
shmatにはマップする先頭アドレスを指定できる。0を指定すると、適当に決めてくれる。複数のプロセスで同じアドレスにマップしたい際は、最初のプロセスで0を使って適当にマップした後、マップしたアドレスをどうにかして別のプロセスに伝え、そのアドレスを引数にshmatを実行する。
ここからちょっとややこしい話。僕の知る限り、HP-UXでは、以上のような手順を踏まなくても同じ共有メモリは複数のプロセスで同じアドレスにマップされる。Linuxではそうでもない。ややこしいのは、(僕の経験では)I/O系のライブラリルーチン中でmmapを使うことがあり(?)、これにより、マップしたいアドレスが使われてしまうことがある。こうなると、複数のプロセスで同じアドレスに共有メモリをおくことができなくなる :-(

こんなもんだったかしらん?また思い出したら追記します。