boost::interprocessのshared_memory_objectとmapped_regionを使ってプロセス間でメモリを共有する

# boost::interprocessを使用したプロセス間のメモリ共有
C++のオープンソースライブラリ、boostを使って共有メモリにデータを書き込んで、プロセス間でデータを共有する方法を学んだので、忘備録を兼ねてサンプルプログラムを書いてみました。

まずは、共有メモリ上にデータを書き込む親プロセスのコードです。

```C++:shm_parent.cpp
#include <iostream>
#include <string>
#include <unistd.h>

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

const std::string childName = "shm_child";      // 子プロセスの実行ファイル名
const std::string shmObjName = "shm_sample";    // 共有メモリオブジェクトの名前
const std::string writeString = "Hello,world."; // 共有メモリに書き込む文字列

void createChildProcess();

int main()
{
  int status;
  pid_t child;

  using namespace boost::interprocess;
  // 共有メモリオブジェクトを作成(書き込み可)
  shared_memory_object shm(create_only, shmObjName.c_str(), read_write);
  // 共有メモリオブジェクトの領域を確保
  shm.truncate(writeString.size());

  // 共有メモリオブジェクトをmapped_regionにマッピング
  mapped_region map(shm, read_write);
  // 共有メモリにアクセスするポインタを取得
  char* shmPtr = static_cast<char*>(map.get_address());
  // 共有メモリへの書き込み
  memcpy(shmPtr, writeString.c_str(), writeString.size());

  if ((child = fork()) < 0)
  {
    std::cerr << "failed to fork child process.\n";
    return 1;
  }

  if (child == 0)
  {
    // 子プロセスを起動
    createChildProcess();
  }
  else
  {
    // 子プロセスの終了を待つ
    if (wait(&status) < 0)
    {
      std::cerr << "wait child process error.\n";
      return 1;
    }
    // 共有メモリオブジェクトを削除
    shared_memory_object::remove(shmObjName.c_str());
  }

  return 0;
}

void createChildProcess()
{
  execve(childName.c_str(), nullptr, nullptr);
}

```

共有メモリへのデータの書き込みは、以下の5ステップで行います。

###shared_memory_objectインスタンスの作成
```C++
using namespace boost::interprocess;
shared_memory_object shm(create_only, shmObjName.c_str(), read_write);
```

shared_memory_objectのコンストラクタには、以下の3つの引数を渡します。
####1.作成モード
共有メモリオブジェクトを作成する際の挙動を指定します。
#####create_only
メモリファイルを新規作成します。すでに同名のファイルが存在する場合には、例外が送出されます。
#####open_or_create
メモリファイルが存在する場合にはそれを読み込み、存在しなければ新規作成します。
#####open_only
メモリファイルの読み込みのみを行います。ファイルが存在しない場合は、例外が送出されます。

####2.共有メモリファイル名
作成、または読み込みを行うメモリファイルの名前を指定します。

####3.読み込み/書き込みモード
読み込み/書き込みモードのを指定します。指定できるのは、read_writeまたはread_onlyの2つです。

###mapped_regionインスタンスの作成
```C++
mapped_region map(shm, read_write);
```
mapped_regionのコンストラクタには、shared_memory_objectと読み込み/書き込みモードの2つを指定します。

###共有メモリへのポインタを取得
```C++
char* shmPtr = static_cast<char*>(map.get_address());
```
mapped_regionのget_address()関数を呼び、共有メモリへのポインタを取得します。
void*型のポインタが返されるので、適切な方にキャストします。
今回は文字列を書き込むので、char*型にstatic_castでキャストしておきます。

###共有メモリへのポインタを取得
```C++
memcpy(shmPtr, writeString.c_str(), writeString.size());
```
最後に、memcpyなどの関数でデータをポインタに書き込みます。

次に、子プロセス側のコードです。

```C++:shm_child.cpp
#include <iostream>

#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

const std::string shmObjName = "shm_sample"; // 共有メモリオブジェクトの名前

int main(int argc, char* argv[])
{
  using namespace boost::interprocess;
  // 共有メモリオブジェクトを読み込み(読み込みのみ)
  shared_memory_object shm(open_only, shmObjName.c_str(), read_only);

  // 共有メモリオブジェクトをmapped_regionにマッピング
  mapped_region map(shm, read_only);

  // 共有メモリにアクセスするポインタを取得
  char* shmPtr = static_cast<char*>(map.get_address());

  // 読み込んだ文字列(Hello,world.)を表示
  std::cout << shmPtr << std::endl;

  return 0;
}
```

基本的な流れは書き込み側とほとんど変わりません。
共有メモリからデータの読み込みを行うので、モードにはopen_only, read_onlyを指定しておきます。