こんにちは!システムエンジニア歴5年のキョンです。今回は「C++での共有メモリ」について、実務での経験を交えながら詳しく解説していきます。
目次
共有メモリとは?
共有メモリ(Shared Memory)は、複数のプロセス間でメモリ領域を共有するための仕組みです。普段の開発では別々のプロセスは互いのメモリにアクセスできませんが、共有メモリを使うと、異なるプロセス間でデータをやり取りできるんです。
なぜ共有メモリを使うの?
1. 高速なデータ共有
- プロセス間通信の中で最速
- メモリ直接アクセスが可能
- データコピーが不要
2. リアルタイム性が求められる場合
- ゲーム開発
- 動画処理
- センサーデータの処理
3. 大量データの共有
- ビッグデータ処理
- 科学技術計算
- リアルタイム分析
POSIXでの共有メモリ実装例
1. 共有メモリの作成と接続
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <iostream>
// 共有メモリの構造体
struct SharedData {
int count;
char message[256];
};
// 共有メモリの作成
int createSharedMemory() {
// 共有メモリのファイルディスクリプタを作成
int shm_fd = shm_open("/myshm", O_CREAT | O_RDWR, 0666);
if (shm_fd == -1) {
std::cerr << "shm_open failed" << std::endl;
return -1;
}
// サイズを設定
if (ftruncate(shm_fd, sizeof(SharedData)) == -1) {
std::cerr << "ftruncate failed" << std::endl;
return -1;
}
return shm_fd;
}
2.メモリのマッピング
SharedData* mapSharedMemory(int shm_fd) {
// メモリをマッピング
SharedData* shared_data = (SharedData*)mmap(
NULL,
sizeof(SharedData),
PROT_READ | PROT_WRITE,
MAP_SHARED,
shm_fd,
0
);
if (shared_data == MAP_FAILED) {
std::cerr << "mmap failed" << std::endl;
return nullptr;
}
return shared_data;
}
3.書き込み側プロセス
int main() {
int shm_fd = createSharedMemory();
if (shm_fd == -1) return 1;
SharedData* shared_data = mapSharedMemory(shm_fd);
if (!shared_data) return 1;
// データを書き込む
shared_data->count = 42;
strncpy(shared_data->message, "Hello from writer!", 256);
// メモリをアンマップ
munmap(shared_data, sizeof(SharedData));
close(shm_fd);
return 0;
}
4.読み取り側プロセス
int main() {
// 既存の共有メモリをオープン
int shm_fd = shm_open("/myshm", O_RDONLY, 0666);
if (shm_fd == -1) {
std::cerr << "shm_open failed" << std::endl;
return 1;
}
SharedData* shared_data = mapSharedMemory(shm_fd);
if (!shared_data) return 1;
// データを読み取る
std::cout << "Count: " << shared_data->count << std::endl;
std::cout << "Message: " << shared_data->message << std::endl;
// クリーンアップ
munmap(shared_data, sizeof(SharedData));
close(shm_fd);
return 0;
}
実務での注意点
1. 同期制御の実装
#include <semaphore.h>
class SharedMemoryManager {
private:
SharedData* data;
sem_t* semaphore;
public:
void write() {
sem_wait(semaphore); // ロック
// データ書き込み
sem_post(semaphore); // アンロック
}
};
2.エラーハンドリング
class SharedMemoryException : public std::runtime_error {
public:
SharedMemoryException(const char* message)
: std::runtime_error(message) {}
};
void safeWrite(SharedData* data, const std::string& message) {
try {
if (!data) throw SharedMemoryException("Invalid shared memory");
strncpy(data->message, message.c_str(), 256);
} catch (const SharedMemoryException& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
}
つまずきやすいポイント
1. メモリリーク防止
- 必ずunmapする
- プロセス終了時のクリーンアップ
- エラー発生時の適切な解放
2. 競合状態の回避
- セマフォやミューテックスの使用
- デッドロックへの注意
- 書き込み/読み取りの同期
3. セキュリティ
- 適切なパーミッション設定
- メモリ破壊の防止
- 不正アクセスの制限
実務での活用例
1. 高速データ処理システム
struct ProcessingData {
double sensorData[1024];
int status;
time_t timestamp;
};
2.マルチプロセスアプリケーション
struct AppState {
int activeUsers;
bool isMaintenanceMode;
char systemMessage[512];
};
まとめ
共有メモリは高速なプロセス間通信を実現できる強力な機能です。ただし:
- 適切な同期制御
- エラーハンドリング
- セキュリティ対策 が重要です。
よくある質問(FAQ)
Q1. 共有メモリのサイズ制限は?
A1. システムによって異なりますが、/proc/sys/kernel/shmmax で確認できます。
Q2. 他のIPC手法と比べて何が違う?
A2. 直接メモリアクセスで高速、ただし同期制御が必要です。
Q3. プロセス終了後のクリーンアップは?
A3. shm_unlink()で明示的に削除するか、システム再起動で自動的に解放されます。
コメント