トップページ > 記事閲覧
マルチスレッドとSetUseASyncLoadFlag
名前:てらす 日時: 2013/09/06 01:42

非同期でファイルを丸ごとメモリに読み込む機能を、SetUseASyncLoadFlagでTRUEを 指定した時のLoadGraphなどと似たような使い勝手の関数で実装しようとしています。 そこで、SetUseASyncLoadFlagとFileRread系関数の組み合わせより、マルチスレッド化 してしまったほうが早いと思い、その方法で試してみました。 その際、画像等はSetUseASyncLoadFlag(TRUE);とLoadGraphで非同期読み込みを行ってたのですが、 SetUseASyncLoadFlag(TRUE);のままサブスレッドを作成、サブスレッド内でFileRread系 関数でファイルの読み込みを行った時、FileRead系関数はサブスレッドに対して同期で動作して いるように見える(FileRead_readなどの戻り値が同期の時と同じ)なのですが、これはたまたまでしょうか? 実際のところは同期、非同期どちらで動作するのでしょうか? (メインスレッドではSetUseASyncLoadFlag(TRUE)とSetUseASyncLoadFlag(FALSE)が何度も実行されています) 上記は私の目的に合った動作なのですが、意図した(予測した)動作とは違っていたので、 このまま進めていいものかどうか不安になり質問させていただきました。 そもそも、関数の使い方があっているのかどうかすらわかりません。 もっと効率のいい実装法が有りましたら恐れ入りますが教えていただけないでしょうか? もしくは、図々しい限りで申し訳ないんですが、1度呼ぶだけで非同期でopen→readなど→closeまで面倒を 見てくれる関数を実装していただけないでしょうか? よろしくお願いします。 ※DxLib_Init()の前にSetMultiThreadFlag( TRUE );は実行し、 サブスレッドはCreateThreadで作成しています。 ファイルはDXアーカイブにまとめてしまう予定なのでfopen系は使えません。 予定されるアーカイブの大きさがかなり大きくなる(500MB程度)ので DXArchivePreLoadなども使えません。
メンテ

Page: 1 |

Re: マルチスレッドとSetUseASyncLoadFlag ( No.1 )
名前:管理人 日時:2013/09/07 14:28

SetUseASyncLoadFlag の設定は全スレッド共通ですので( というかDXライブラリは 複数スレッドからライブラリの関数を呼ばれることを想定していないので )、 恐らく作成したスレッドで FileRead系の関数を呼んだ時点で SetUseASyncLoadFlag( FALSE ) ;の 状態になっていたのではないかと思います > もしくは、図々しい限りで申し訳ないんですが、1度呼ぶだけで非同期でopen→readなど→closeまで面倒を > 見てくれる関数を実装していただけないでしょうか? その関数良いかもと思ったのですが、ファイルの内容を格納するメモリはどうしましょう? ファイルサイズを取得するのも非同期で行うとすると、結局非同期でファイルサイズ取得が終了するまで待ってから ファイルサイズ分のメモリを確保し、その後ファイル読み込みを非同期で行うということになると、 結局ステップが減るだけであまり恩恵は無い( 非同期処理の管理はそんなに楽にならない )ような気がします・・・
メンテ
Re: マルチスレッドとSetUseASyncLoadFlag ( No.2 )
名前:てらす 日時:2013/09/09 23:08

お疲れ様です。 回答ありがとうございます。 やはり、たまたまそうなっていただけなのですね。 そのままでは問題が出ること間違いなしなので、現在は各FileRead系関数の後に while( CheckHandleASyncLoad( fileHandle ) == TRUE ){ Sleep( 1 ); } を追加して対応することにしました。 FileRead系関数実行中にメインスレッドでSetUseASyncLoadFlagが呼ばれた時や 複数のスレッドから同時にFileRead系関数が呼ばれた時に 正常に動作するか不安では有りますが・・・ 現在作っているゲームの設計上、FileRead系関数が複数同時に呼ばれることはなく、 今のところは特に問題なく動いているので、それを応急措置としてこのまま進めたいと思います。 (いずれ問題が出そうではありますが、ここで止まってもいられないので) > その関数良いかもと思ったのですが、ファイルの内容を格納するメモリはどうしましょう? > ファイルサイズを取得するのも非同期で行うとすると、結局非同期でファイルサイズ取得が終了するまで待ってから > ファイルサイズ分のメモリを確保し、その後ファイル読み込みを非同期で行うということになると、 > 結局ステップが減るだけであまり恩恵は無い( 非同期処理の管理はそんなに楽にならない )ような気がします・・・ すいません。正直何も考えずに提案してしまっていたので、自分でも少し考えてみました。 ファイル読み込みとそのためのメモリ確保や開放はDXライブラリで行い、グラフィックやサウンドと同じようにハンドルを返し、 そのハンドルを使ってデータを受け渡すとかはどうでしょうか? // ファイルを読み込み、ハンドルを返す int XXXXLoad ( const TCHAR *FileName // ファイルパス ); // 読み込んだファイルからデータを受け取る int GetXXXX ( void *Buf, // データを受け取るバッファ int Size, // 受け取るデータ量(*Bufのサイズ、バイト数) int Offset, // データをどの位置から受け取るか(バイト数) int XXXXHandle // XXXXLoadで受け取ったハンドル ); // 読み込んだデータを消す int DeleteXXXX( int XXXXHandle // XXXXLoadで受け取ったハンドル ); DXライブラリ的にはこんな感じでしょうか。 後は読み込んだファイルサイズを取得する関数を用意したりですかね。 プログラミングは全て独学でやってきているので、これで非同期の恩恵が受けられるのか、 実はFileRead系関数とやっていることは同じなんじゃないか、などと思い始めてよくわからなくなっていますが・・・ (DxLib_Endで開いたファイル全てに対してFileRead_closeしていたらやっていることはほとんど同じですよね)
メンテ
Re: マルチスレッドとSetUseASyncLoadFlag ( No.3 )
名前:管理人 日時:2013/09/13 01:10

ご提案して頂いた機能を実装してみました <追加した関数> // 指定のファイルの内容を全てメモリに読み込み、その情報のアクセスに必要なハンドルを返す // ( 戻り値 -1:エラー -1以外:ハンドル ) // 使い終わったらハンドルは FileRead_fullyLoad_delete で削除する必要があります int FileRead_fullyLoad( const TCHAR *FilePath ) ; // FileRead_fullyLoad で読み込んだファイルのハンドルを削除する int FileRead_fullyLoad_delete( int FLoadHandle ) ; // FileRead_fullyLoad で読み込んだファイルの内容を格納したメモリアドレスを取得する void * FileRead_fullyLoad_getImage( int FLoadHandle ) ; // FileRead_fullyLoad で読み込んだファイルのサイズを取得する LONGLONG FileRead_fullyLoad_getSize( int FLoadHandle ) ; <Test1.bmp を非同期で読み込んで画面に表示するサンプルプログラム> #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int ghandle ; void *image ; int size ; int fhandle ; // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1; // ファイルの非同期読み込み SetUseASyncLoadFlag( TRUE ) ; fhandle = FileRead_fullyLoad( "Test1.bmp" ) ; SetUseASyncLoadFlag( FALSE ) ; // 読み込み終了待ち while( ProcessMessage() == 0 && CheckHandleASyncLoad( fhandle ) ){ Sleep( 1 ) ; } // 読み込んだ内容が格納されているメモリ領域の先頭アドレスとファイルサイズの取得 image = FileRead_fullyLoad_getImage( fhandle ) ; size = FileRead_fullyLoad_getSize( fhandle ) ; // グラフィックハンドルの作成 ghandle = CreateGraphFromMem( image, size ) ; // 読み込んだファイルの解放 FileRead_fullyLoad_delete( fhandle ) ; // 画面に作成したグラフィックハンドルで描画 DrawGraph( 0, 0, ghandle, TRUE ) ; // キー入力待ち WaitKey() ; // DXライブラリの後始末 DxLib_End(); // ソフトの終了 return 0; } 非同期処理待ちが一度で済むのが利点です 確かに open, seek, tell, read それぞれに非同期処理終了待ちするより処理効率も良さそうです こちらにアップしましたので、よろしければお試しになってみてください m(_ _)m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_DevCppTest.exe // Dev-C++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCC_MinGWTest.exe // MinGW 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // .NET用 http://homepage2.nifty.com/natupaji/DxLib/DxLibMakeTest.exe // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
メンテ
Re: マルチスレッドとSetUseASyncLoadFlag ( No.4 )
名前:てらす(解決) 日時:2013/09/13 23:08

お疲れ様です。 実装された関数を試したところ、私の目指していたものを妥協なしに再現することが出来ました。 使い勝手もよく、これでファイルの種類を気にせずに非同期読み込みを行うことが出来ます。 お忙しい中、本当にありがとうございました。
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存