• ベストアンサー
  • 困ってます

メモリマップドファイルは動作原理的に…

QueryPerformanceCounterを使ってそれほど複雑でない関数でのベンチマークを行ったところ 今のところ全ての場合においてメモリマップドファイルのほうが単純なファイルの読み書きより高速でした。 (こんないい機能があったなんて…(笑)) それほど差がない場合もありましたが、場合によっては100倍以上もの差になった時もあります。(実メモリと比較したら全然ではありますが) メモリに困ることは最近それほどなかったので、、仮想メモリのスワップアウトが起きるとどれくらいの速度で動作することになるのか 全く実感できなかったのですが 1.このメモリマップドファイルは 原理的に、それを明示的に行うようなものとみなして問題ないでしょうか? 2.書き込み可能な属性で作り CreateFileMappingに指定するサイズがファイルサイズより大きかった場合はファイルが拡張され、それ以下だった場合はそのままのようです。 しかし、実際にそれ未満の数値を指定して、その指定したサイズ以上のアドレスのところへ書き込もうとすると、メモリの場合サクッと不正終了してくれるので逆におかしいところがあることが分かるので安心できるともいえるのですが、こちらはファイルサイズに余裕があれば、指定したサイズを超えた部分へもどうやら書き換えることができてしまうようです。 この場合、もしファイルサイズすら超えた数値へ間違って書き込み命令を出してしまった場合、切り捨てられるのでしょうか?それともどこか別のところが書き換えられてしまう危険があるのでしょうか? 3.また、試したら出来てしまったのですが 別のポインタを使って操作するのは「通常の動作」でしょうか? それとも未定義の動作でしょうか? 例) ・ ・ ・ char *a = (char*)MapViewOfFile( hMap, FILE_MAP_WRITE , 0, 0, 0); wsprintf(a,"aaaaaa"); char *b= a+3; wsprintf(b,"bbbbbb"); b+=3; wsprintf(b,"ccc"); UnmapViewOfFile( a ); ・ ・ ・ 結果: aaabbbccc

共感・応援の気持ちを伝えよう!

  • 回答数3
  • 閲覧数4052
  • ありがとう数7

質問者が選んだベストアンサー

  • ベストアンサー
  • 回答No.3
  • rinkun
  • ベストアンサー率44% (706/1571)

えーと、質問ではMapViewOfFileでマッピングサイズに0を指定していますが、この場合はマッピングオブジェクト全体がアドレス空間にマップされます。CreateFileMappingとファイルもサイズ0だとエラーになりますので、マッピングオブジェクトはある程度の大きさを持っているはずです。質問の例は意図せずファイル範囲内になっている可能性があります。 あとマップサイズがページサイズ(4KB)の倍数でない場合、端数分は範囲を超えてもアクセス例外は出ないでしょう。また範囲を超えたらアクセス例外が起きることに期待するのは間違いです。そのアドレスにたまたま何か有効な変数に割り当てられているとアクセス例外にはなりませんから。 マップした範囲内なら反映までにある程度の遅延はあるにしてもファイルに反映されます。範囲外だとアクセス例外が出るか、何も出ずに書き込めてしまうかは分かりません。書き込めてもファイルには反映されないと思いますが、無関係な変数を壊している可能性はあります。 4.通常の動作としてはファイルを指定していればそのファイルをマップするのでスワップファイルへのマップはないと思いますが、仕様に明記されていないので保証はできません。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

ありがとうございます。 MapViewOfFileについては、上記コードは不正終了しなかった一例として書いただけですので、実際には色々と実験していました。 …が、4KBの倍数にしてはいませんでした。 実際に4KBにしてそれを超えたところへ書き込もうとしてみると、見事に「不正終了」してくれました! また >範囲を超えたらアクセス例外が起きることに期待するのは間違い というのを確認できれば十分です。 一見必要そうな状況があった場合に、そのために変数を用意する必要が本当にあるかどうかが一番の気がかりだったわけですが 通常のメモリと同じように書き込み範囲のサイズを保存しておく方が万全ならば、その変数を「別の場所でも活用した」処理をさせることを考えられれば、パフォーマンス上も全然十分だと思います。 4についても、イメージ通りのようで、安心しました。 これで安心して先に進めそうです。

関連するQ&A

  • case で宣言コンパイルエラー

     switch (msg){  case WM_LBUTTONDOWN:   char *p = new char[1000];   wsprintf(p, "%d" , i);   MessageBox(hWnd , p , "" , MB_OK);   delete[] p;  break; がエラーで  switch (msg){  case WM_LBUTTONDOWN:   char *p;   p = new char[1000];   wsprintf(p, "%d" , i);   MessageBox(hWnd , p , "" , MB_OK);   delete[] p;  break; と  switch (msg){  case WM_KEYDOWN:   if( wParam == VK_RETURN ){    char *p = new char[1000];    wsprintf(p, "%d" , i);    MessageBox(hWnd , p , "" , MB_OK);    delete[] p;   }  break; ならエラーじゃなかったんだけど、理由がよく分かりません。 case のすぐ下で宣言と同時に値を代入してはいけないんですか?

  • WINAPIでのキー入力した文字列の比較について

    以前ここで教えていただいた wsprintf( input, "%s%c", input, (int)wp ); を使って文字列の比較判定を行ないたいのですが WM_CHAR内で wsprintf( input, "%s%c", input, (int)wp ); wsprintf( ans, "%s", input); check= strcmp(que ,input); //queはファイルからのアルファベット文字列 if(check == 0){ //正解した時の処理 } else{ 不正解だった時の処理 } としているのですが一文字入力するごとにelseに引っかかって上手くいきません,どうすればいいでしょうか? よろしくお願いします。

  • wsprintf( ) でポインタに代入

    wsprintf(p, "%d" , i); を書いたせいで、i の値が変わります。 wsprintf(p, "%d" , i); によってどんなことが起こっているのか詳しく知りたいです。 ポインタのことがまだよく分かってないんです。 #include <windows.h> LPCSTR szStr = "\n char c[255];\n char *p = \"\\0\";\n int i = 12345;\n\n switch (msg){\n case WM_LBUTTONDOWN:\n  wsprintf(c, \"%d\" , i);\n  wsprintf(p, \"%d\" , i);\n  MessageBox(hWnd , c , \"\" , MB_OK);\n break;"; LRESULT CALLBACK WndProc(HWND , UINT , WPARAM , LPARAM); int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE , LPSTR , int){ 省略 return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wParam , LPARAM lParam){ HDC hDC; PAINTSTRUCT ps; RECT rt; char c[255]; char *p = "\0"; int i = 12345; switch (msg){ case WM_LBUTTONDOWN: wsprintf(c, "%d" , i); wsprintf(p, "%d" , i); MessageBox(hWnd , c , "" , MB_OK); break; case WM_PAINT: GetClientRect(hWnd, &rt); hDC = BeginPaint(hWnd, &ps); DrawText(hDC, szStr, lstrlen(szStr), &rt, DT_WORDBREAK); EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return(DefWindowProc(hWnd , msg , wParam , lParam)); } return (0L); }

その他の回答 (2)

  • 回答No.2
  • hidebun
  • ベストアンサー率50% (92/181)

#1さんの1.→FlushViewOfFileかと。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

ありがとうございます。 リモートコンピュータではFlushViewOfFileを普通に呼んでも同期が保証されないようですが 私の目的はローカルコンピュータなのでそれで同期が保証されるようですね。 もちろん >CreateFile 関数を使ってファイルを開く際に FILE_FLAG_WRITE_THROUGH フラグを指定すると、物理的な書き込みが完了した後で FlushViewOfFile が制御を返すようになります。 とMSDNに書いてあるので、リモートでやりたいならそうすればOKですね。

  • 回答No.1
  • rinkun
  • ベストアンサー率44% (706/1571)

1. メモリマップドファイルは、プロセスのアドレス範囲を利用できるようにする機能です。同時にそのアドレス範囲のスワップアウト先を指定ファイルにすることができます。 なお、マップしたメモリへの書き込みは必ずしも即座にファイルに反映されるわけではないので注意してください。ファイルでもフラッシュが必要なように、同期APIの呼び出しが必要です。 # 同期APIの名称を思い出せない。アンマップ時しか同期できないかも 2. 書き込み可能マップを作ると、書き込みの有無に関わらずファイルはそのサイズまで拡大されます。逆にマップ作成時に指定したサイズを超えてのアクセスはアクセス例外になります。 3. メモリマップドファイルは、プロセスの指定アドレス範囲を利用可能にします。プロセスで利用可能なアドレス空間をプロセス内のどのポインタでアクセスしても有効です。

共感・感謝の気持ちを伝えよう!

質問者からのお礼

ありがとうございます。 やはり明示的に同期させなければ同期が保証されないという点以外は、メモリと同じような扱い方が出来るようですね。 しかし、2のアクセス例外というのは、OSが勝手に握りつぶしてくれる(ファイルのサイズ内なら普通どおりやり、その外だとやめてくれる…?) のでしょうか? 上記のとおりファイル範囲外に代入したようなコードでも不正終了など全く起こらないばかりか、GetLastErrorとか使っても何も捕捉できません。 使用を控えていた try catch で念のため実験(catchは(...)で)してみても、やはり何も例外を受け取りません。 すみません(汗 もうひとつ重大なことを忘れていました。 4.0xFFFFFFFFを指定するとページングファイルを使うことになり それ以外なら普通のファイルを使うことになり、ページングファイルは全く使用しないことが保証されるのでしょうか?

関連するQ&A

  • wsprintf( ポインタ , "%d" , "123" );

    char str[100]; char *ptr; wsprintf(str, "%d", "1234567"); と wsprintf(ptr, "%d", "1234567"); について、 TextOut(hDC,0,10,str,lstrlen(str)); TextOut(hDC,0,30,ptr,lstrlen(ptr)); で出力したいんだけど、str ならできたけど、 ptr の方が文字化けしていました。 lstrlen(ptr); がいけないのかと思って、 その値を調べたら 0 でした。 strlen( ) はポインタに対応していると思いました。 #include <iostream.h> main(){ char *p = "あいう"; cout << strlen(p); } で 6 だったから。 Win32 の lstrlen( ) はポインタに対応していないんですか?

  • ドロップで起動するけどパスは?

    ファイルをEXEにドロップして起動させます。 ドロップしたファイルのパスを GetCommandLine( ) から 取り出すために、" の位置を調べます。 "EXEのパス" ドロップファイルのパス となっているから、2番目の " の位置を調べました。 でも、for でのループが1回で終わってしまいます。 おかしいところを教えてください。 LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {  char *p = GetCommandLine();  char str[200];  switch(msg){  case WM_CREATE:   int i;   for(i = 1; p[i] == '"'; i++);{    wsprintf(str, "%d", p[i]);    MessageBox(hWnd, chStr, "", MB_OK);   }   wsprintf(chStr, "%d", i);   MessageBox(hWnd, str, "", MB_OK); //結果は1   wsprintf(chStr, "%#x", p[0]);   MessageBox(hWnd, str, "1文字目", MB_OK); //結果は34   wsprintf(chStr, "%#x", p[1]);   MessageBox(hWnd, str, "2文字目", MB_OK); //結果は67   wsprintf(chStr, "%#x", p[2]);   MessageBox(hWnd, str, "3文字目", MB_OK); //結果は58

  • wsprintfで実数値を文字列にしたい

    ダイアログボックスの「edit」部分にセットしようと思ったのですが SetDlgItemIntが整数しか使えないので変換したいです。 TCHAR buf[20]; wsprintf(buf, "%.1f", temperature); と書きましたがconst char * の引数LPCWSTRのパラメータと互換性がありませんと出てしまいます。

  • WINAPIでキーから文字列を入力できない

    今,WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)内の case WM_CHAR:で wsprintf(input, "入力=\"%c\"", (int)wp); としているのですが,今の状態では文字列を入力できません。 どうすればいいでしょうか、教えて下さい。

  • wParam

    wParamは、unsigned int型で、仮想キーコードを、格納してますよね。 wsprintf()内で(TCHAR)キャストしてますが、 これは、変数strの型がTCHAR型なので(wParamは、unsigned intなので型をあわせるために)やっているんですか? (TCHAR)キャストしないとエラーになりますか?教えてください。 HDC hdc; TCHAR str[255]; swich(umsg){   case WM_CHAR:     wsprintf( str, TEXT("%c"), (TCHAR)wPara );     hdc = GetDC(hwnd);     TextOut(hdc, 0, 0, str, lstrlen(str));     return0 }

  • Windows APIでおかしな事になる。

    Windows APIでプログラミングをしています。 Windows APIでプログラミングをしています。 char*型の文字列を表示させようと、このように記述しました。 const char * y; y=f(); SelectObject(hdc , hFont); SetBkColor(hdc , RGB(255 , 255 , 255)); wsprintf( str, "名前は、%s", y ); TextOut(hdc , 300, 20, str, lstrlen(str)); すると、表示できたのはいいのですが、 タイトルバーをクリックしてウィンドウを広げたり、別のウィンドウを一番前に持ってきて、 その後、そのウィンドウを出したりすると、エラーが出て、強制終了になってしまします。 何か問題はありますか? ちなみに、strの宣言はこのようになっております。 static TCHAR str[64]; あとですが、 wsprintf( str, "名前は、%s", y ); この部分のyを&yに変えると、エラーは起こりませんが、 変な文字が表示されてしまいます。 ウィンドウを少し操作すると、その文字がまた変な文字に変わります。 何が原因でしょうか。

  • char型変数をLPCTSTR型に変換したい

    大学の研究でプログラム作成している者です. 現在外部ファイルの文字列をfscanf()でchar型変数に取り込み,それをLPCTSTR型変数に変換して,関数に引数として渡そうとしてます. しかし,現在はchar/THCARの変換が正しくできず困っております.現在のコードは以下のような流れになってます. ----------------------------------------------- char name[MAX_PATH]; TCHAR name_t[MAX_PATH]; fscanf( &fp, "%s", name ); wsprintf( name_t, _T("%s"), &name ); // char ⇒ TCHAR makedFunction( name_t ); // 自作関数(引数はLPCTSTR) ----------------------------------------------- しかし, wsprintf()で変換した時点で,文字列がおかしくなってしまい困ってます. 開発環境はVisualStudio2010で,MFC作成(Unicode文字列)となってます.ちなみにマルチバイト文字列を使用する解決方法はなしとします. 解決方法をご存知の方がおられましたら,是非とも,ご回答よろしくお願い致します.

  • 宣言による処理の重さ

    第161章 キーボード・フック http://www.kumei.ne.jp/c_lang/sdk2/sdk_161.htm このサイトのLRESULT CALLBACK MyHookProc(int nCode, WPARAM wp, LPARAM lp)で {   char str[256];   if (nCode < 0)     return CallNextHookEx(hMyHook, nCode, wp, lp);   if (wp >= 0x30 && wp <= 0x39) {     wsprintf(str, "hMyHook = %d", hMyHook);     MessageBox(NULL, str, "MyHookProc", MB_OK);     return CallNextHookEx(hMyHook, nCode, wp, lp);   }   wsprintf(str, "キー入力はインターセプトされました\n フックハンドル= %d", hMyHook);   MessageBox(NULL, str, "インターセプト", MB_OK);   return TRUE; } と書いてありますが、char str[256];をstatic char str[256];にしたり、 {   if (nCode < 0)     return CallNextHookEx(hMyHook, nCode, wp, lp);   if (wp >= 0x30 && wp <= 0x39) {     char str[256];     wsprintf(str, "hMyHook = %d", hMyHook);     MessageBox(NULL, str, "MyHookProc", MB_OK);     return CallNextHookEx(hMyHook, nCode, wp, lp);   }   wsprintf(str, "キー入力はインターセプトされました\n フックハンドル= %d", hMyHook);   MessageBox(NULL, str, "インターセプト", MB_OK);   return TRUE; } にするとアプリケーションのパフォーマンスはよくなりますか?

  • WritePrivateProfileStringについて

    下記コードをOnMouseMove()に記述すると、ちゃんとiniファイルが作成されますが、OnLButtonUp() 内では作成されません。 どうしてなのか教えていただきたいです。 OnLButtonUp() でiniファイルが作成されるようにするにはどうすれば良いでしょうか? どうぞよろしくお願いいたします。 ************************ void CMyWnd::OnMouseMove(UINT nFlags, CPoint point) { // *********ウインドウを移動するたびにウィンドウ位置を保存 int nX,nY;//ウィンドウの左上の座標を格納する変数 WINDOWPLACEMENT wp;//WINDOWPLACEMENT構造体 char szBuffer[32];//キーの値を格納する char aaa[10]; wp.length = sizeof(WINDOWPLACEMENT); GetWindowPlacement(&wp); nX = wp.rcNormalPosition.left; nY = wp.rcNormalPosition.top; wsprintf(aaa,"%d",nn); wsprintf(szBuffer,"%d",nX); WritePrivateProfileString(aaa,"X",szBuffer,"d:\\kado.ini"); wsprintf(szBuffer,"%d",nY); WritePrivateProfileString(aaa,"Y",szBuffer,"d:\\kado.ini"); nn--; CWnd::OnMouseMove(nFlags, point); }

  • 共有メモリへのマッピング(MapViewOfFile)について

    共有メモリについて(特にMapViewOffileについて)教えてください。 ある構造体と、あるデータAを共有メモリへマッピングしたい考えています。 構造体は、 typedef struct _Data { int length; long data; char mIntArrayData[256]; } Data; データAは、short型の配列(要素数はx*y*z,x,y,zはcsvファイル等から読み込む)で、サイズをdatasize = sizeof(short) * x * y * z;とします。 この2つを使って、 両方のデータを long AllDataSize = sizeof(Data) + datasizeとしました。 このサイズを使って、共有メモリのマップハンドルを hMap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,PAGE_READWRITE,AllDataSize,MAPPED_FILE_NAME); (MAPPED_FILE_NAMEは、 メモリマップドファイルの名前) で、生成しました。 生成はできたのですが、データAにアクセスするための下記のような時にマッピングに失敗してしまいました。 DWORD dwOffset = sizeof(DATA); short *pData = (short *)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, dwOffset, Bytes); (Bytesはマッピングしたいバイト数でsizeof(short)の倍数) 次のようなDATAにアクセスするマッピングには成功しています。 DWORD dwOffset = 0; DATA *pDATA = (DATA *)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, dwOffset, sizeof(DATA)); 色々なサイト等を調べて、考えてみたのですが、怪しいところはdwOffsetと、CreateFileMappingで、マッピングしたい全体のファイルサイズを、構造体とデータAのサイズの単純な足し算としているところと考えています。ただ、はっきりとした答えが全くわからないので、どうか御教授お願いします。