MENU

【C++】共有メモリによるプロセス間通信について~概要とサンプルコード~

この記事では、共有メモリを用いたプロセス間通信について紹介します。

共有メモリによるプロセス間通信は、Unix系システムでよく使われる方法の一つです。

共有メモリを使うことで、プロセス間でデータをやり取りすることができます。ここでは、C++での共有メモリによるプロセス間通信の概要と簡単な実装例を紹介します。

目次

共有メモリの概要

共有メモリを使用したプロセス間通信 は、複数のプロセスが同じメモリ空間を共有することで、データを高速にやり取りする方法です。

共有メモリの基本的な操作手順

  1. 共有メモリオブジェクトの作成
  2. 共有メモリサイズの設定
  3. 共有メモリのマッピング
  4. 共有メモリへのアクセス
  5. 共有メモリのアンマッピング
  6. 共有メモリオブジェクトの削除

実装例

C++では、共有メモリを利用するためにPOSIX (Portable Operating System Interface) かSystem VのいずれかのAPIを使用します。ここでは、POSIXを用いた基本的な実装例を紹介します。

以下の例では、2つのプロセスが共有メモリを介して整数値をやり取りします。

#include <iostream>
#include <fcntl.h> // For O_* constants
#include <sys/mman.h>
#include <sys/stat.h> // For mode constants
#include <unistd.h>
#include <cstring>

const char *SHM_NAME = "/my_shared_memory";
const size_t SHM_SIZE = sizeof(int);

void writer_process() {
    // 共有メモリオブジェクトを作成
    int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) {
        std::cerr << "Failed to create shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリのサイズを設定
    if (ftruncate(shm_fd, SHM_SIZE) == -1) {
        std::cerr << "Failed to set size of shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリをマップ
    void *shm_ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shm_ptr == MAP_FAILED) {
        std::cerr << "Failed to map shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリにデータを書き込む
    int *shared_data = static_cast<int*>(shm_ptr);
    *shared_data = 42;

    std::cout << "Data written to shared memory: " << *shared_data << std::endl;

    // 共有メモリをアンマップ
    if (munmap(shm_ptr, SHM_SIZE) == -1) {
        std::cerr << "Failed to unmap shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリオブジェクトを閉じる
    if (close(shm_fd) == -1) {
        std::cerr << "Failed to close shared memory object" << std::endl;
        exit(1);
    }
}

void reader_process() {
    // 共有メモリオブジェクトを開く
    int shm_fd = shm_open(SHM_NAME, O_RDONLY, 0666);
    if (shm_fd == -1) {
        std::cerr << "Failed to open shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリをマップ
    void *shm_ptr = mmap(0, SHM_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
    if (shm_ptr == MAP_FAILED) {
        std::cerr << "Failed to map shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリからデータを読み取る
    int *shared_data = static_cast<int*>(shm_ptr);
    std::cout << "Data read from shared memory: " << *shared_data << std::endl;

    // 共有メモリをアンマップ
    if (munmap(shm_ptr, SHM_SIZE) == -1) {
        std::cerr << "Failed to unmap shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリオブジェクトを閉じる
    if (close(shm_fd) == -1) {
        std::cerr << "Failed to close shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリオブジェクトを削除
    if (shm_unlink(SHM_NAME) == -1) {
        std::cerr << "Failed to unlink shared memory object" << std::endl;
        exit(1);
    }
}

int main() {
    pid_t pid = fork();
    
    if (pid < 0) {
        std::cerr << "Fork failed" << std::endl;
        return 1;
    } else if (pid == 0) {
        // 子プロセス
        sleep(1); // 親プロセスが書き込みを完了するのを待つ
        reader_process();
    } else {
        // 親プロセス
        writer_process();
    }

    sleep(3);

    return 0;
}

ヘッダーファイルのインクルード

#include <iostream>
#include <fcntl.h> // For O_* constants
#include <sys/mman.h>
#include <sys/stat.h> // For mode constants
#include <unistd.h>
#include <cstring>

iostreamは標準入力出力のため、fcntl.hはファイルコントロール用、sys/mman.hはメモリマッピング用、sys/stat.hはファイルモード用、unistd.hはPOSIX API用、cstringはC文字列操作用です。

定数の定義

const char *SHM_NAME = "/my_shared_memory";
const size_t SHM_SIZE = sizeof(int);

ここでは、共有メモリの名前とサイズを定義しています。共有メモリの名前は/my_shared_memory、サイズは整数型の大きさ(`sizeof(int))です。

writer_process関数

void writer_process() {
    // 共有メモリオブジェクトを作成
    int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666);
    if (shm_fd == -1) {
        std::cerr << "Failed to create shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリのサイズを設定
    if (ftruncate(shm_fd, SHM_SIZE) == -1) {
        std::cerr << "Failed to set size of shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリをマップ
    void *shm_ptr = mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    if (shm_ptr == MAP_FAILED) {
        std::cerr << "Failed to map shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリにデータを書き込む
    int *shared_data = static_cast<int*>(shm_ptr);
    *shared_data = 42;

    std::cout << "Data written to shared memory: " << *shared_data << std::endl;

    // 共有メモリをアンマップ
    if (munmap(shm_ptr, SHM_SIZE) == -1) {
        std::cerr << "Failed to unmap shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリオブジェクトを閉じる
    if (close(shm_fd) == -1) {
        std::cerr << "Failed to close shared memory object" << std::endl;
        exit(1);
    }
}

この関数は、共有メモリを作成し、そこに整数データを書き込みます。

reader_process関数

void reader_process() {
    // 共有メモリオブジェクトを開く
    int shm_fd = shm_open(SHM_NAME, O_RDONLY, 0666);
    if (shm_fd == -1) {
        std::cerr << "Failed to open shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリをマップ
    void *shm_ptr = mmap(0, SHM_SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
    if (shm_ptr == MAP_FAILED) {
        std::cerr << "Failed to map shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリからデータを読み取る
    int *shared_data = static_cast<int*>(shm_ptr);
    std::cout << "Data read from shared memory: " << *shared_data << std::endl;

    // 共有メモリをアンマップ
    if (munmap(shm_ptr, SHM_SIZE) == -1) {
        std::cerr << "Failed to unmap shared memory" << std::endl;
        exit(1);
    }

    // 共有メモリオブジェクトを閉じる
    if (close(shm_fd) == -1) {
        std::cerr << "Failed to close shared memory object" << std::endl;
        exit(1);
    }

    // 共有メモリオブジェクトを削除
    if (shm_unlink(SHM_NAME) == -1) {
        std::cerr << "Failed to unlink shared memory object" << std::endl;
        exit(1);
    }
}

この関数は、共有メモリから整数データを読み取ります。

main関数

int main() {
    pid_t pid = fork();
    
    if (pid < 0) {
        std::cerr << "Fork failed" << std::endl;
        return 1;
    } else if (pid == 0) {
        // 子プロセス
        sleep(1); // 親プロセスが書き込みを完了するのを待つ
        reader_process();
    } else {
        // 親プロセス
        writer_process();
    }

    // 3秒間待機
    sleep(3);

    return 0;
}

main関数では、forkでプロセスを作成し、前述の2つの関数を実行させています。

実行結果

以下のコマンドでプログラムを実行します。

./<実行ファイル名>

以下のように共有メモリを使用してプロセス間通信ができていることが確認できます。

Data written to shared memory: 42
Data read from shared memory: 42
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

20代の組み込みソフトウェアエンジニア
主な使用言語はC++

---------------------資格---------------------
応用情報技術者
ネットワークスペシャリスト

目次