忘れないようにもう少し詳しく書いておく
$ man shm_overview
の最後の方にも書かれているように、System V系のshmget等のAPIは古いんだそうだ。一方でPOSIX系が実装されていないケースもあるから、うにゃらうにゃらということです。今回のケースでは一応想定プラットフォームでは実装済みということもあり、POSIXに準拠する事にしました。
そうすると、おおざっぱなながれとしては
共用メモリの準備
shm_openして、ftruncateで完了。
共用メモリの使用
shm_openして、mmapして、使い終わったらmunmapで終わり。
共用メモリの開放
shm_unlinkで終わり。
System V 系との違い
shmget等での利用はユニークなkeyを前提に設計されている。一方で、POSIX系は /dev/shm の下に作られるデバイスファイルによる管理。デバイスファイルの名前を指定して共用メモリを同定させるというわけ。同じ名前でも別の共用メモリを使いたい場合は、ユーザー名やら別個のIDやらを振って使うようにしているみたいですね。少なくともUbuntuの/dev/shm以下を見てみると。
共用メモリが本当に割り振られているのか、サイズは十分なのか?はそのディレクトリの内容を ls してみればだいたい確認できるし、手続きの簡略化が本当に良いことなのかどうか?はケースバイケースにしろ、今回の目的にはこれで十分機能している。
競合もあまり気にしなくてもよさそうだし。
参照との兼ね合い
こういう事が出来ればいいな、と思う。
void *ptr = mmap( .., sizeof( ClassA ) );
if( ptr == MAP_FAILED ){
// ... error happen
}
// map されたメモリ上のデーターをClassAオブジェクトとして利用
ClassA& objA = *( (ClassA*) ptr );
共用メモリ上にクラスオブジェクトを配置するというわけ。
でもポインタ変数でやるよりも、C++には「参照」なるものがあるから、
オブジェクト変数として扱えるほうがなんぼかまし。
「まし」というよりも、C++の先生はポインタなんか使うなと言っていた。
これでうまくいくというのがナイーブな理解だったわけ。ところが、
参照を経由してアクセスすると、どうやらローカル変数として振舞ってしまう。
まったく共用されていない。
ちなみに、上記サンプルで、ふつーに
ClassA *objA = (ClassA*) ptr;
とキャストしてあげれば、なにも問題なくいきます。
もしかしたらキャストのやり方の問題かな?とも思わないでもないけど、またいつか確認してみよう。
同じような問題はスレッド間のグローバル変数でも。
スレッドクラスをつくってあげて、スレッド間で同じメンバー変数を「共用メモリ」的に使おうと思ったわけ。メソッドにメンバー変数の参照を返す関数を用意しておいて、親スレッドでは参照経由でメンバー変数にアクセスした。
この場合でも参照を経由してしまうと、グローバル変数でもスレッド間での共用が出来なくなる。
もしかしたら調査が不十分で、なにか別の要因で起きていた減少なのかもしれないけど、「参照」って便利な分なかなかに厄介な面もある事を知った。
ROOTのマクロでの「参照」
多分同じ所に根をもつ問題かもしれないが、ROOTのマクロでも参照がうまく動かない場合がある。 const を無視してくれるのはいいとしても、期待した動作をしない原因が参照にあって、コピー渡しで解決した事がある。
マクロを実行する場合に、いったいどんな事をしているのかわからないのだけど、変数の取り扱い、に関する事が絡んでくるのであれば、十分あり得る現象なのかな?と思い初めている所。