親・子プロセス間でのメモリ共有(プロセス間通信)

親プロセスから生成された子プロセスは、親プロセスが持っていたメモリ(変数)のコピーを持ちます。したがって、親・子プロセス両方から読み書き可能なメモリ領域を作って情報をやりとりする必要があります。それを実現するのが共有メモリです。

共有メモリの取得後、削除せずに終了した場合、その共用メモリはOSが終了するまで残ってしまいます。このようなメモリはipcsコマンドで見ることができ、ipcrmにより削除することが可能です。

今回の例題では a(int型)のデータのみ共用していますが、共有する情報は構造体にまとめて共用するのが便利であるため、共用メモリは構造体で宣言しています。

例題の動作は、親プロセスにより子プロセスが終了するのを待ち、a が 0 でなければプログラムを終了し、メモリを削除、a が 0 であれば、再びプロセスを作成し同じ処理を続行するようになっています。

ipcs,ipcrm 実行例
Gami[108]% ipcs

---------- Shared Memory Segments --------
     shmid     key       bytes     nattch    status
_shm 1664      0         4         1                   ---> 削除せずに残ったメモリ

---------- Semaphore Arrays --------
     semid     nsems     key

---------- Message Queues --------
     msqid     used-bytes  messages

Gami[109]% ipcrm shm 1664                              ---> メモリの削除
Gami[110]% ipcs

---------- Shared Memory Segments --------
     shmid     key       bytes     nattch    status

---------- Semaphore Arrays --------
     semid     nsems     key

---------- Message Queues --------
     msqid     used-bytes  messages

Gami[111]%

例題に用いた関数
shmget()共有メモリの識別子を得る
shmat() 自プロセスのメモリとして割り当てる
shmdt() 自プロセスのメモリから外す
shmctl()共有メモリの制御を行う(共有メモリの削除も可能)

親・子プロセス間でのメモリ共有(プロセス間通信)list_38.c)
/*=======================================================
  親・子プロセス間でのメモリー共有(プロセス間通信)
  =======================================================*/

#include <stdio.h>
#include <sys/shm.h>

///////////////////////////////////////////////////////
// 構造体定義
///////////////////////////////////////////////////////
// 共有情報
struct sharememory
{
    int a;
};
// 共有メモリー用構造体
struct sharememory_info
{
    int    id;               /* 共有メモリー識別子 */
    struct sharememory *shm; /* 共有情報           */
};

///////////////////////////////////////////////////////
// 関数プロトタイプ宣言
///////////////////////////////////////////////////////
int release_sharemem(int id, struct sharememory *shm);
///////////////////////////////////////////////////////

int main(int argc, char *argv[])
{
    int pid,endflg=0;
    struct sharememory_info shmem_inf;

    /* 共有メモリー識別子取得 */
    if(( shmem_inf.id = shmget(IPC_private,
                               sizeof(struct sharememory),
                               IPC_CREAT|0666)) == -1) {
        perror("shmget");
        return 0;
    }

    /* 共有メモリーアタッチ */
    if((int)(shmem_inf.shm =(void *)shmat(shmem_inf.id, 0, 0)) == -1) {
        perror("shmat");
        release_sharemem(shmem_inf.id, shmem_inf.shm);
        return 0;
    }
    
    /* 共有メモリー初期化 */
    shmem_inf.shm->a = 0;
    
    /* 更新前出力 */
    printf("a = %d\n", shmem_inf.shm->a);

    while(endflg==0){
        /* 子プロセス起動 */
        if((pid = fork()) < 0) {
            perror("fork");
            release_sharemem(shmem_inf.id, shmem_inf.shm);
            return 0;
        }
        
        /* 子プロセス */
        if(pid == 0) {
            /* 共有メモリーアタッチ */
            if((int)(shmem_inf.shm =(void *)shmat(shmem_inf.id, 0, 0)) == -1) {
                perror("shmat");
                release_sharemem(shmem_inf.id, shmem_inf.shm);
                _exit(0);
            }
            
            printf("cchild: input a: ");
            scanf("%d",&shmem_inf.shm->a);
            
            /* 共有メモリーデタッチ */
            shmdt(shmem_inf.shm);
            
            _exit(0);
        }
        
        /* 親プロセス */
        if(pid > 0) {
            /* 子プロセスが終了するのを待つ */
            wait(NULL);
            if(shmem_inf.shm->a) endflg=1;
            /* 更新後出力 */
            printf("a = %d\n",shmem_inf.shm->a);
        }
    }
    /* 終了処理 */
    release_sharemem(shmem_inf.id, shmem_inf.shm);

    return 0;
}

int release_sharemem(int id, struct sharememory *shm)
{
    /* 共有メモリーデタッチ */
    if(id >= 0) {
        shmdt(shm);
    }
    /* 共有メモリー識別子削除 */
    if(shmctl(id, IPC_RMID, 0) == -1) {
        perror("shmctl");
        exit(-1);
    }
    return 1;
}
実行結果
Gami[140]%./list_38.exe
a = 0
cchild: input a: 0
a = 0
cchild: input a: 0
a = 0
cchild: input a: 0
a = 0
cchild: input a: 0
a = 0
cchild: input a: 0
a = 0
cchild: input a: 1
a = 1
Gami[141]%
inserted by FC2 system