SunOS 5.9 オペレーティングシステムで共有メモリーアプリケーションを実装するには、mmap(2) とシステムの内蔵仮想メモリー機能を利用する方法が最も効率的です。詳細は、第 1 章「メモリー管理」を参照してください。
SunOS 5.9 は System V 共有メモリーもサポートしますが、物理メモリーのセグメントを複数のプロセスの仮想アドレス空間に接続する方法としては最適ではありません。複数のプロセスに書き込みアクセスが許可されているときは、セマフォなどの外部のプロトコルやメカニズムを使用して、不整合や衝突などを回避できます。
プロセスは、shmget(2) を使用して共有メモリーセグメントを作成します。この呼び出しは、既存の共有セグメントの ID を取得する際にも使用できます。作成プロセスは、セグメントのアクセス権と大きさ (バイト数) を設定します。
共有メモリーセグメントの元の所有者は、shmctl(2) を使用して所有権をほかのユーザーに割り当てることができます。所有者はこの割り当てを取り消すこともできます。適切なアクセス権を持っていれば、ほかのプロセスも shmctl(2) を使用して共用メモリーセグメントにさまざまな制御機能を実行できます。
共有メモリーセグメントを作成した後は、shmat(2) を使用してプロセスのアドレス空間にセグメントを接続できます。切り離すには shmdt(2) を使用します。プロセスを接続するには shmat(2) に対しての適当なアクセス権を持つ必要があります。接続すると、プロセスは接続操作で要求されているアクセス権に従って、セグメントの読み取りまたは書き込みを実行できます。共有セグメントは、同じプロセスによって何回でも接続できます。
共有メモリーセグメントは、物理メモリー内のある領域を指す一意の ID を持つ制御構造体から成ります。セグメント ID は shmid と呼びます。共有メモリーセグメントの制御構造体は sys/shm.h に定義されています。
shmget(2) を使用して、共有メモリーセグメントへアクセスします。成功すると、共有メモリーセグメント ID (shmid) を返します。次のコードに、shmget(2) の使用例を示します。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
...
key_t key; /* shmget() に渡す key */
int shmflg; /* shmget() に渡す shmflg */
int shmid; /* shmget() からの戻り値 */
size_t size; /* shmget() に渡すサイズ */
...
key = ...
size = ...
shmflg) = ...
if ((shmid = shmget (key, size, shmflg)) == –1) {
perror("shmget: shmget failed");
exit(1);
} else {
(void) fprintf(stderr,
"shmget: shmget returned %d\n", shmid);
exit(0);
}
...
shmctl(2) を使用して、共有メモリーセグメントのアクセス権とその他の特性を変更します。cmd 引数は、次の制御コマンドのいずれか 1 つです。
|
SHM_LOCK |
指定したメモリー内の共有メモリーセグメントをロックする。このコマンドを実行するプロセスは、有効なスーパーユーザーの ID を持つ必要がある |
|
SHM_UNLOCK |
共有メモリーセグメントのロックを解除する。このコマンドを実行するプロセスは、有効なスーパーユーザーの ID を持つ必要がある |
|
IPC_STAT |
制御構造体にある状態情報を取得して、buf が指すバッファーに入れる。このコマンドを実行するプロセスは、セグメントの読み取り権を持つ必要がある |
|
IPC_SET |
有効なユーザー ID およびグループ ID とアクセス権を設定する。このコマンドを実行するプロセスは、所有者、作成者、またはスーパーユーザーの有効な ID を持つ必要がある |
|
IPC_RMID |
共有メモリーセグメントを削除する。このコマンドを実行するプロセスは、所有者、作成者、またはスーパーユーザーの有効な ID を持つ必要がある |
次のコードに、shmctl(2) の使用例を示します。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
...
int cmd; /* shmctl() のためのコマンドコード */
int shmid; /* セグメント ID */
struct shmid_ds shmid_ds; /* 結果を保持するための共有メモリーデータ構造体 */
...
shmid = ...
cmd = ...
if ((rtrn = shmctl(shmid, cmd, shmid_ds)) == –1) {
perror("shmctl: shmctl failed");
exit(1);
...
共有メモリーセグメントの接続と切り離しを行うには、shmat() と shmdt() を使用します(shmop(2) のマニュアルページを参照)。shmat(2) は、共有セグメントの先頭へのポインタを戻します。shmdt(2) は、shmaddr で指定されたアドレスから共有メモリーセグメントを切り離します。次のコードに、shmat(2) と shmdt(2) の呼び出しの使用例を示します。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
static struct state { /* 接続されるセグメントの内部レコード */
int shmid; /* 接続されるセグメントの ID */
char *shmaddr; /* 接続点 */
int shmflg; /* 接続時に使用されるフラグ */
} ap[MAXnap]; /* 現在接続されているセグメントの状態 */
int nap; /* 現在接続されているセグメント数 */
...
char *addr; /* アドレス用の作業変数 */
register int i; /* 作業領域*/
register struct state *p; /* 現在の状態エントリへのポインタ */
...
p = &ap[nap++];
p–>shmid = ...
p–>shmaddr = ...
p–>shmflg = ...
p–>shmaddr = shmat(p->shmid, p->shmaddr, p->shmflg);
if(p–>shmaddr == (char *)-1) {
perror("shmat failed");
nap–-;
} else
(void) fprintf(stderr, "shmop: shmat returned %p\n",
p–>shmaddr);
...
i = shmdt(addr);
if(i == –1) {
perror("shmdt failed");
} else {
(void) fprintf(stderr, "shmop: shmdt returned %d\n", i);
for (p = ap, i = nap; i–-; p++) {
if (p–>shmaddr == addr) *p = ap[–-nap];
}
}
...