ホーム

OFF-SOFT.net

OFF-SOFT.net

ウェブやソフトウェアに関するサポート&情報サイトです。サイト構築からソフトウェアの作成、利用まであなたの助けになるかも・・・・しれません。たぶん・・。

Boost(3)メモリマップを使ってみる

公開日| 2009年09月09日 | コメントはまだありません。
概要 :
 今回の記事は、メモリマップ(共有メモリ(Shared Memory))をBoostで使ってみます。
メモリマップは、WIndowsでは、APIが用意されていますので、結構、使われています。そのメモリマップと同じ動作をするようにBoostでは、どのように記述すれば良いか、簡単に記述したいと思います。

では、早速、サンプルソースを使って試してみましょう。
ここで使用するプログラムは、Boostのサンプルソースを判りやすく、一部、変更したものです。


オリジナルのサンプルソース :


ここで使用したサンプルソースコード:

コンソールアプリケーションで試してみましょう
簡単に動作確認するために、上記のオリジナルサンプルを、少しだけ、わかりやすいように変更してみました。
では、早速、ソースコードを見てみましょう。

[sample.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>
#include <string>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <cstdlib> //std::system
#include <sstream>
 
using namespace std;
using namespace boost;
using namespace boost::interprocess;
 
//	const data
const char * MMMAP_NAME = "MySharedMemory";
int max_share_size = 65536;
int real_share_size = 1024;
 
int main (int argc, char *argv[])
{
	if(argc == 1){ 
		shared_memory_object::remove(MMMAP_NAME);
		// Create a managed shared memory segment
		managed_shared_memory segment(create_only, MMMAP_NAME, max_share_size);
 
		// Allocate a portion of the segment (raw memory)
		std::size_t free_memory = segment.get_free_memory();
		void * shptr = segment.allocate(real_share_size);
 
		// Check invariant
		if(free_memory > segment.get_free_memory()){
 
			char *pbuff=(char *)shptr;
			pbuff[0]='A';
			pbuff[1]='B';
			pbuff[2]='C';
			pbuff[3]=NULL;
 
			// convert memory to handle
			managed_shared_memory::handle_t handle = segment.get_handle_from_address(shptr);
			// set of child process param .
			std::stringstream s;
			s << argv[0] << " " << handle;
			s << std::ends;
			cout << "handle:"  << handle << endl;
			// Launch child process
			int nchild = std::system(s.str().c_str());
 
			cout << "child return:"  << nchild << endl;
			cout << "changed?:"<< pbuff << endl;
 
			//	delete share memory
			segment.deallocate(pbuff);
 
			string sdata;
			cin >> sdata ;	//	any key input!! --> exit.
 
			//	delete share memory
			shared_memory_object::remove(MMMAP_NAME);
 
		} else {
			//	delete share memory
			shared_memory_object::remove(MMMAP_NAME);
 
			return 1;
		}
	} else {
		//Open managed segment
		managed_shared_memory segment(open_only, MMMAP_NAME);
 
		//An handle from the base address can identify any byte of the shared 
		//memory segment even if it is mapped in different base addresses
		managed_shared_memory::handle_t handle = 0;
 
		//Obtain handle value
		std::stringstream s; s << argv[1]; s >> handle;
 
		// Get buffer local address from handle
		void *msg = segment.get_address_from_handle(handle);
 
		char *pbuff=(char *)msg;
 
		cout << "origin:" << pbuff << endl;
 
		//	change data!!
		pbuff[0]='D';
		pbuff[1]='E';
		pbuff[2]='F';
		pbuff[3]=NULL;
 
	}
	return 0;
}

このプログラムは、引数なしで起動すると、自動的に子プロセス(同じプログラム:引数にハンドル番号が指定される)を起動して メモリマップの情報が、両方のプロセスで読み書きできるかを試したものです。

では、簡単に解説をしてみます。
19行目は、メモリマップに同じ名前を使用できないので、その名前のメモリマップがあれば、削除しています。
21行目は、メモリマップを新規に作成しています。引数には、名前と最大メモリサイズを指定します。
24行目は、作成したメモリマップの空きメモリサイズを確認しています。
25行目は、作成したメモリマップで、本当に使う領域を確保しています。
28行目は、作成したメモリマップで、本当に使う領域をと空き領域の差を確認しています。
空き領域より、本当に使う領域が大きくなってしまっている場合は、異常と判断しています。

30行目からは、メモリマップの領域に情報を書き込んでいます。
37行目は、子プロセスへ情報を渡すためのハンドル情報を取得しています。
44行目は、子プロセスを起動しています。


66行目からが、子プロセスの処理です。
ここでは、メモリマップを開いて、引数でもらったハンドルから、領域のアドレスを取得しています。(76行目まで)
80行目で、実際の中身を出力して、情報が読めているか確認します。
83行目からは、今度は、書き込みをしています。

親プロセスは、47行目で、変更された情報が読めるか確認しています。


実際に、実行してみると、以下がその実行結果が表示されます。

1
2
3
4
handle:96
origin:ABC
child return:0
changed?:DEF

思ったとおりに、読み書きができました。


Boostでは、このように、メモリを認識するためにハンドル情報を使います。 ハンドル情報の受け渡しが必要になってしまうのでは、他プロセス間通信を行うのには、少々不便ですね。
Windowsのメモリマップのように固定文字列のみで、読み書きできようにするためには、どうするのでしょう。

ちゃんと、それも用意されています。Boostでは、オブジェクトでのやり取りをするように設計されています。

25行目を、以下のように、変更します。
1
MyClass *myclass = segment.construct<MyClass>("MyClassObject")();


また、取り出すときは、76行目を以下のような感じで変更すると、該当オブジェクトのアドレスを取得できます。
1
2
std::pair<CMemMappedData*, std::size_t> res=segment.find<CMemMappedData>("MyClassObject");
MyClass *myclass = res.first;

ここで使うMyClassは、独自に作成することができますが、そのクラスでは、new や mallocなどをやってメモリ確保をしても 共有できないので、注意が必要です。

メモリを動的に確保したい場合は、先の例のように、managed_shared_memoryのallocateを使い、ハンドル情報を属性に持たせて共有すれば良いでしょう。



もっと、Boostについて詳しく知りたい方は、以下の本なども良いと思います。
本から学ぶことは多いと思います。ネットだけでは判らない様々な事に気づかされます。


コメント

コメントをどうぞ







  • はてなブックマークへ追加する
  • Facebookでシェアする
  • twitter でつぶやく
  • Google Plusでシェアする
  • Pocketでシェアする
ページトップへ