プログラミングインタフェース

System V 共有メモリー

SunOS 5.10 オペレーティングシステムで共有メモリーアプリケーションを実装するには、mmap(2) とシステムの内蔵仮想メモリー機能を利用する方法がもっとも効率的です。詳細は、第 1 章メモリーと CPU の管理を参照してください。

SunOS 5.10 は 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;       /* key to be passed to shmget() */
        int       shmflg;    /* shmflg to be passed to shmget() */
        int       shmid;     /* return value from shmget() */
        size_t    size;      /* size to be passed to 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;                 /* command code for shmctl() */
int     shmid;               /* segment ID */
struct  shmid_ds  shmid_ds;  /* shared memory data structure to hold results */
        ...
        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 { /* Internal record of attached segments. */
        int           shmid;        /* shmid of attached segment */
        char          *shmaddr;     /* attach point */
        int           shmflg;       /* flags used on attach */
} ap[MAXnap];                       /* State of current attached segments. */
int     nap;                        /* Number of currently attached segments. */
...
char    *addr;                      /* address work variable */
register int          i;            /* work area */
register struct state *p;           /* ptr to current state entry */
...
        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];
                 }
        }
...