ページ 11

メモリマップトファイル

Posted: 2013年2月12日(火) 23:57
by Cユーザー
以下のコードで正しく共有されなくて困っています。
共有メモリに関するDLLを作成し、プロセスAとプロセスBで使用します

コード:

//Samle.dll

long SampleClass::Create()
{
	//共有メモリを作成
	m_handle = CreateFileMapping(
					INVALID_HANDLE_VALUE,
					NULL,
					PAGE_READWRITE,	// 読書き両方にする
					0,
					100,
					"test"// 共有メモリ名を設定
					);

	// マッピング開始
	m_adress = (INFO_DATA *)MapViewOfFile(
					m_handle,
					FILE_MAP_ALL_ACCESS, // 読書き両方
					0,
					0,
					100);

	if(m_adress == NULL)
	{
		return -1;
	}

	m_adress->headerinfo.size = 100;
	m_adress->lineinfo	= (LINE_INFO*)( (DWORD)m_adress +sizeof(HEADER_INFO) );
	return 0;
}

long SampleClass::Open()
{
	m_handle = OpenFileMapping(
					FILE_MAP_ALL_ACCESS, 
					FALSE, 
					 "test");

	if(m_handle == NULL)
	{
		return -1;
	}

	HEADER_INFO* h = (HEADER_INFO *)MapViewOfFile(m_handle,
					FILE_MAP_ALL_ACCESS, // 読書き両方
					0,
					0,
					sizeof(HEADER_INFO));

	// マッピング開始
	m_adress = (INFO_DATA *)MapViewOfFile(m_handle,
					FILE_MAP_ALL_ACCESS, // 読書き両方
					0,
					0,
					h->size);

	if(m_adress == NULL)
	{
		return -1;
	}


	return 0;
}

long SampleClass::Destroy()
{
	if( ( m_adress == NULL ) || ( m_handle == NULL ) )
	{
		return -1;
	}

	//マッピング解除
	UnmapViewOfFile(m_adress);
	//ハンドル閉じ
	CloseHandle(m_handle);
	m_handle = NULL;

	return 0;
}

void SampleClass::Write(char* str)
{
	m_adress->lineinfo->lineNumber = 1;
	strcpy_s(m_adress->lineinfo->strData, str);
}

INFO_DATA* SampleClass::GetData()
{
	return m_adress;
}


順序として

①プロセスAで共有メモリ作成

//プロセスA

SampleClass s;
void CSampleADlg::OnBnClickedButton1()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
s.Create();//①
}

②プロセスBで共有メモリオープン
③プロセスBで共有メモリに書き込み
//プロセスB

SampleClass s;
void CSampleBDlg::OnBnClickedButton1()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
s.Open();//②
s.Write("hello");//③
}

④プロセスAでデータの確認
void CSampleADlg::OnBnClickedButton2()
{
// TODO: ここにコントロール通知ハンドラ コードを追加します。
INFO_DATA * info = s.GetData();
}

この手順で確認したところ文字列が入っておりませんでした。

何故共有されないのでしょうか?

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 00:04
by softya(ソフト屋)
共有メモリ上にポインタが有るように見えますが、プロセスごとに論理アドレス空間が違う共有メモリにはポインタは使えませんよ。

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 00:13
by Cユーザー
共有メモリにポインタを使っているので共有化されない
ということですか?

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 00:25
by Cユーザー
先頭アドレスm_adressからsizeof(ヘッダー)分ずらした位置を覚えてるのですが
まずいのかな

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 00:45
by softya(ソフト屋)
Windowsなどの仮想記憶の仕組みを理解してもらう必要がありそうです。
「仮想記憶 - Wikipedia」
http://ja.wikipedia.org/wiki/%E4%BB%AE% ... 8%E6%86%B6

プロセスAにとって意味のあるポインタ値でもプロセスBにとっては意味のない不正規なポインタ値となります。
なぜなら前にも書いた通り論理アドレスが違うからです。

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 00:53
by Cユーザー
いやその仮想メモリの話はわかるのですが、それを共有するようにする仕組みがメモリマップトファイルと思ってたのですが・・うーん

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 00:59
by softya(ソフト屋)
メモリマップトファイルは、仮想記憶メモリを共有するための仕組みです。
普通のプロセスは、仮想記憶メモリを共有していませんので、お互いの内容は参照できません。

【補足】
プロセスAとプロセスBでマッピングされている論理アドレスが違うはずです。
プロセスAで0x200000だったとして、プロセスBで0x210000だとします。
プロセスAで0x200010と言う値のポインタ値をつくってマッピングされたメモリに書き込んだとしましょう。
それをプロセスBで参照すると0x200010は割り当てられていないメモリですからエラーになるでしょうって事です。

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 01:37
by Cユーザー
なんとなくわかります。

ただちょっと一番私の理解のネックになっているのが
ポインタであればNGとのことなのでポインタの場合は先ほど説明していただいた理由でエラーになる

ポインタでなければどういう仕組みでマッピングされるのでしょうか。
そこのポインタである場合とポインタでない場合のメモリマッピングの違いがイマイチぴんときません。

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 10:49
by softya(ソフト屋)
Cユーザー さんが書きました:なんとなくわかります。

ただちょっと一番私の理解のネックになっているのが
ポインタであればNGとのことなのでポインタの場合は先ほど説明していただいた理由でエラーになる

ポインタでなければどういう仕組みでマッピングされるのでしょうか。
そこのポインタである場合とポインタでない場合のメモリマッピングの違いがイマイチぴんときません。
よく分かっておられない様なので、デバッガでプロセスAとプロセスBの次のポインタ値を調べて書きだして下さい。
そして書きだしたアドレスを見て考察してみて下さい。

m_adress
&(m_adress->lineinfo)
&(m_adress->lineinfo->lineNumber)
&(m_adress->lineinfo->strData)
m_adress->lineinfo->strData

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 10:55
by YuO
Cユーザー さんが書きました:いやその仮想メモリの話はわかるのですが、それを共有するようにする仕組みがメモリマップトファイルと思ってたのですが・・うーん
softya(ソフト屋) さんが書きました:メモリマップトファイルは、仮想記憶メモリを共有するための仕組みです。
Memory mapped fileはファイル (の一部) をメモリ空間に擬似的に割り付けて,ポインタでのファイルアクセスを可能にするための仕組み,です。

なんで,「file」という言葉があるのにファイルを扱うための仕組みが本質であることを無視するかなぁ,と思ったり。
元々ファイルへのアクセスなので,論理アドレスがプロセス毎に異なっても当然だし,ポインタを含めることが実質的にできないのも当然なのですが……。
# 後者はファイルにポインタ値を出力して,それを別のプロセスで利用するのか?という話。
Cユーザー さんが書きました:ポインタでなければどういう仕組みでマッピングされるのでしょうか。
そこのポインタである場合とポインタでない場合のメモリマッピングの違いがイマイチぴんときません。
構造体等にポインタがあろうが無かろうが,仕組みは変わりません。
そのメモリの情報をプログラムがどう認識するかは,プログラムに任されています。
  • 「ファイル」 or 「物理メモリ」 or 「物理メモリからページアウトされたデータ」はプロセス間で共有される
  • 上記をプロセスのメモリ空間に割り付ける「ページング情報」は,プロセス毎に異なる
  • 「ページング情報」が異なるため,一番上の「データ」が割り付けられる「論理アドレス」はプロセス毎に異なる
というのが,前提となる知識で,その上で,
  • Windows (に限らず,x86/x64上の大抵のOS) では,セグメント・セレクタは実質機能しておらず,コンパイラは「ポインタの値」を「論理アドレス」そのまま使用している
  • 先に記述した通り,「論理アドレス」はプロセス毎に異なる
  • よって,「ポインタの値」をプロセスを越えて共有しても意味がない
というのが,共有メモリ中でポインタが使えない理由です。

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 11:02
by softya(ソフト屋)
前に書き添えたのですが忘れられたので、もう一度書いておきます。
「メモリマップトファイル • C言語交流フォーラム ~ mixC++ ~ バイナリファイルで別プログラムにデータを受け渡すプログラムを書いて見ることをオススメします」
http://dixq.net/forum/viewtopic.php?t=1 ... 871#p99878
バイナリファイルでプログラム間でデータを受け渡せない技術力ではメモリ共有など早すぎます。

あと、SampleClassってプロセス同期の仕組みが入っていないんですが別にやってますよね?

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 14:37
by Cユーザー
すいません、ありがとうございました

Re: メモリマップトファイル

Posted: 2013年2月13日(水) 14:57
by softya(ソフト屋)
Cユーザー さんが書きました:すいません、ありがとうございました
この間から堂々めぐりしてますので、ここで締め切らず理解できるまでやってはどうでしょうか?
また同じ事を繰り返すと思いますので、この機会にちゃんと理解されたほうが良いとおもいます。

それと解決コードを提示されていないので、フォーラムルール義務違反でもあります。