boost::interprocessを使用したプロセス間のメモリ共有
C++のオープンソースライブラリ、boostを使って共有メモリにデータを書き込んで、プロセス間でデータを共有する方法を学んだので、忘備録を兼ねてサンプルプログラムを書いてみました。
まずは、共有メモリ上にデータを書き込む親プロセスのコードです。
#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インスタンスの作成
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インスタンスの作成
mapped_region map(shm, read_write);
mapped_regionのコンストラクタには、shared_memory_objectと読み込み/書き込みモードの2つを指定します。
###共有メモリへのポインタを取得
char* shmPtr = static_cast<char*>(map.get_address());
mapped_regionのget_address()関数を呼び、共有メモリへのポインタを取得します。
void型のポインタが返されるので、適切な方にキャストします。
今回は文字列を書き込むので、char型にstatic_castでキャストしておきます。
###共有メモリへのポインタを取得
memcpy(shmPtr, writeString.c_str(), writeString.size());
最後に、memcpyなどの関数でデータをポインタに書き込みます。
次に、子プロセス側のコードです。
#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を指定しておきます。