SunOS 5.8 オペレーティングシステムで共用メモリアプリケーションを実装するには、mmap(2) 関数と固有仮想記憶管理を利用する方法が最も効率的です。第 6 章「メモリ管理」 を参照してください。
SunOS 5.8 では、System V 共用メモリもサポートされます。共用メモリを使用すると、複数のプロセスが同時に物理メモリの 1 つのセグメントを自分の仮想アドレス空間に接続できますが、効率は低下します。複数のプロセスに書き込みアクセスが許可されているときは、セマフォなどの外部のプロトコルや機構を使用して、不一致や衝突などを防止できます。
プロセスは、shmget(2) を使用して共用メモリセグメントを作成します。この呼び出しは、既存の共用セグメントの ID を取得する際にも使用できます。作成プロセスは、セグメントのアクセス権と大きさ (バイト数) を設定します。
共用メモリセグメントの元の所有者は、shmctl(2) を使用して所有権を他のユーザに割り当てることができます。この関数では割り当てを取り消すこともできます。適切なアクセス権を持っていれば、他のプロセスも shmctl(2) を使用して共用メモリセグメントに様々な制御機能を実行できます。
共用メモリセグメントを作成すると、shmat(2) を使用してプロセスのアドレス空間に接続できます。切り離すには shmdt(2) を使用します。接続するプロセスが shmat(2) のための適当なアクセス権を持っていなければなりません。接続してしまうと、プロセスは接続操作で要求されているアクセス権に従って、セグメントの読み取りまたは書き込みを実行できます。共用セグメントは、同じプロセスによって何回でも接続できます。
共用メモリセグメントは、物理メモリ内のある領域を指す一意の 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 を持っていなければならない。 |
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]; } } ... |