読者です 読者をやめる 読者になる 読者になる

意味悲鳴

PythonとかUnityとか.技術ブログでしたが,研究ブログにシフトしました.

【C言語】親子プロセス間で共有メモリを使う

C言語

もうやだ。とりあえずクソみたいなソースコードを。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>

#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)

void child(void);

int main()
{
        int *test_num;
        int *test_ptr;
        int pid = 0;
        int status = 0;

        int fd, fde, ret, rete;

        fd = shm_open("/shared_memory",  O_CREAT | O_RDWR, FILE_MODE);
        fde = errno;
        if(fd == -1)
        {
                fprintf (stderr, "shm_open failed. err=%s\n\n", strerror (fde));
                exit (EXIT_FAILURE);
        }

        ret = ftruncate (fd, sizeof(int));
        rete = errno;

        test_ptr = mmap (0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if(test_ptr == MAP_FAILED)
        {
                fprintf (stderr, "mmap failed\n");
                exit (EXIT_FAILURE);
        }

        test_num = (int*)test_ptr;
        printf("parent : test_num = %d\n", *test_num);


        pid = fork();
        if(pid == -1)
        {
                err(EXIT_FAILURE, "fork failure");
        }
        else if(pid == 0)
        {
                printf("child process start\n");
                child();
        }else
        {
                pid = wait(&status);
                printf("parent : test_num = %d\n", *test_num);

                if (ret = shm_unlink ("/shared_memory"))
                {
                        fprintf (stderr, "shm_unlink(shm_struct) failed\n");
                        exit (EXIT_FAILURE);
                }

                return EXIT_SUCCESS;
        }

        return 0;
}

void child()
{
        int *test_num;
        int *test_ptr;
        int pid = 0;

        int fd, fde, ret, rete;

        fd = shm_open("/shared_memory", O_RDWR, FILE_MODE);
        fde = errno;
        if(fd == -1)
        {
                fprintf (stderr, "shm_open failed. err=%s\n", strerror (fde));
                exit (EXIT_FAILURE);
        }

        ret = ftruncate (fd, sizeof(int));
        rete = errno;

        test_ptr = mmap (0, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        if(test_ptr == MAP_FAILED)
        {
                fprintf (stderr, "mmap failed\n");
                exit (EXIT_FAILURE);
        }

        test_num = (int*)test_ptr;
        *test_num = 0;

        printf("child : test_num = %d\n",*test_num);

        *test_num = 1;

        printf("child : test_num = %d\n",*test_num);

        return;
}

手順は大体そのまんまなんだけど一応書いておくと、

shm_open()で共有メモリを宣言
ftruncate()でサイズを変更(サンプルコードによっては大きめだったので、適宜変更すればいいと思います)
mmapでポインタに割り当て
使う前に適切な型にキャスト
あとは適当に

だいたいこんな感じ。
引っかかったところは、mmapの返り値が(void *)型なので、いちいちキャストしてあげないといけないところ。これ忘れるとみんな大好きsegmentation fault起こす。
改めて読むと無駄な部分(test_ptr → test_numのあたりとか)多い気がするけど、私の能力では何やっても動かなくなりそうなのでこれで勘弁してください。
というかPOSIX関連、というよりC言語関連の情報が古かったり見つからなかったりで本当に辛い。みんなこんなのわかって当然ってことなんだろうか。恐ろしい話である。

参考文献はこちら。

POSIX / Semapho のメモ

ものぐさ備忘録 : mmap

Posix共有メモリ - s-kitaの日記

解きながら学ぶC言語

解きながら学ぶC言語

新版 明解C言語 入門編

新版 明解C言語 入門編