Posix共有メモリ

Posix.1では、無関係なプロセス間でのメモリ共有を行う方法を2種類提供している。

  • 1.メモリマップファイル(memory-mapped files): ファイルをopenし、結果のファイルディスクリプタmmapでプロセスのアドレス空間にマップする

  • 共有メモリオブジェクト(shared memory objects): shm_openでIPC名をオープンし、返されたディスクリプタmmapでプロセスのアドレス空間にマップする





  • shm_open関数、shm_unlink関数

    Posix共有メモリの使用には、2ステップの処理が必要。
  • 1.名前引数を与えてshm_openを呼び出す

  • 2.mmapを呼び出し、共有メモリを呼び出したプロセスのアドレス空間にマップする
  • shm_openで用いた名前引数は、このメモリを他のプロセスから共有する場合に用いる名前になる。

    #include <sys/mman.h>
    
    int shm_open(const char *name, int oflag, mode_t mode);
    int shm_unlink(const char *name);
    
    戻り値:成功なら0、エラーなら−1

  • nameは、IPC名

  • oflagは、O_RDONLYまたはO_RDWRを指定する必要あり。O_CREAT, O_EXCL, O_TRUNCを追加できる。

  • modeには許可ビットを指定し、O_CREATフラグが指定された場合に用いられる。shm_openでは、常にmode引数が必要。O_CREATが指定されていない場合、modeにはゼロを指定できる。
  • shm_openの戻り値は、mmapの第5引数に与えるディスクリプタ

  • shm_unlinkは、共有メモリオブジェクトの名前を削除する




  • ftruncate関数、fstat関数

    mmapを用いる際には、通常ファイルまたは共有メモリオブジェクトのサイズを、ftruncateで変更することができる。

    #include <unistd.h>
    
    int ftruncate(int fd, off_t length);
    
    戻り値:成功なら0、エラーなら−1

    ftruncateの定義について

  • 通常ファイルに対して:lengthがファイルサイズより小さい場合、余分なデータが削除されファイルは縮小する。lengthがファイルサイズより大きい場合、ファイルサイズの拡張が行われるかどうかは定義されていない。しかし、大半の実装では、ftruncateでファイルサイズを拡張することができる。

  • 共有メモリオブジェクトに対して:ftruncateは、そのオブジェクトの大きさをlengthに設定する。


  • ディスクリプタを指定して、そのディスクリプタの情報を取得する

    #include <sys/types.h>
    #include <sys/stat.h>
    
    int fstat(int fd, struct stat *buf);
    
    戻り値:成功なら0、エラーなら−1

    fdが共有メモリオブジェクトを参照している場合に意味を持つのは、4つのメンバのみ

    struct stat {
        mode_t st_mode;
        uid_t st_uid;
        gid_t st_gid;
        off_t st_size;
    };
    //Posix共有メモリ
    
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdio.h>
    
    #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)
    
    
    void
    write_shm()
    {
        int i, fd;
        struct stat stat;
        unsigned char *ptr;
        fd = shm_open("/posix_shm", O_RDWR|O_CREAT, FILE_MODE);  
        ftruncate(fd, 1024);
        fstat(fd, &stat);
        ptr = mmap(NULL,
                stat.st_size,
                PROT_READ|PROT_WRITE,
                MAP_SHARED,
                fd,
                0);
        close(fd);
        //Write
        for (i = 0; i < stat.st_size; i++) {
            *ptr++ = i % 256;
        }
    }               
    
    void
    read_shm()
    {
        int i, fd;
        struct stat stat;
        unsigned char c, *ptr;
    
        fd = shm_open("/posix_shm", O_RDONLY, FILE_MODE);
        fstat(fd, &stat);
        ptr = mmap(NULL,
            stat.st_size,
            PROT_READ,
            MAP_SHARED,
            fd,
            0);
        close(fd);
    
        for (i = 0; i < stat.st_size; i++) {
            if ( (c = *ptr++) != (i % 256) ) {
                printf("error : ");
            }
            printf("ptr[%d] = %d\n", i, c);
        }
       
        return;
    }
    
    
    int
    main()
    {
        write_shm();
        read_shm();
        return 0;
    }
    



    //Posix共有メモリを用いたメモリマップファイル上の
    //カウンタ増加
    #include <sys/mman.h>
    #include <stdio.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <semaphore.h>
    
    #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)
    
    struct shmstruct {
        int count;
    };
    
    sem_t *mutex;
    
    
    void
    init()
    {
        int fd;
        struct shmstruct *ptr;
        shm_unlink("/posix_shm");
        fd = shm_open("/posix_shm", 
                 O_RDWR|O_CREAT|O_EXCL, 
                 FILE_MODE);
        ftruncate(fd, sizeof(struct shmstruct));
        ptr = mmap(NULL,
            sizeof(struct shmstruct),
            PROT_READ|PROT_WRITE,
            MAP_SHARED,
            fd,
            0);
        close(fd);
        sem_unlink("/sem");
        mutex = sem_open("/sem", O_CREAT|O_EXCL, FILE_MODE, 1);
        sem_close(mutex);
    }
    
    
    int
    main()
    {
        init();
       
        int fd, i, nloop;
        pid_t pid;
        struct shmstruct *ptr;
    
        nloop = 1000;
        fd = shm_open("/posix_shm", O_RDWR, FILE_MODE);
        ptr = mmap(NULL,
                sizeof(struct shmstruct),
                PROT_READ|PROT_WRITE,
                MAP_SHARED,
                fd,
                0);
        close(fd);
    
        mutex = sem_open("/sem", 0);
        pid = getpid();
        for (i = 0; i < nloop; i++) {
            sem_wait(mutex);
            printf("pid %ld: %d\n", (long)pid, ptr->count++);
            sem_post(mutex);
        }
       
        return 0;
    }