言語:C++
windowsのReadFile関数を使用して非同期のファイル読み込みをしようと、以下のコードを書いたのですがどうもReadFileが非同期ではなく同期になっているように思えます。
コードのAsyncReadFIle::CreateAsyncReadFile()で非同期読み込みを開始しているつもりなのですが、
適当な重いファイル(例えばVS2010が自動的に出力するsdfファイル、37MB、コピーして使用)を読み込ませて非同期読み込みができているかどうか確かめました。
プログラムの動作時間をミリ秒で出力するclock()でReadFile()を挟んで計測したところ、実行に500msほどかかっていることが分かりました。
同じファイルを2度以上読み込んだ場合はかなり早くなっていましたが、キャッシュされたためと予想し名前を変更しながら計測をしました。
ReadFile()の実行に500msも時間がかかっていることと、ReadFile()の戻り値が0でGetLastError()はERROR_IO_PENDINGを返しているものの、
その後すぐにGetOverlappedResult()で取得した読み込み済みのサイズがGetFIleSize()の結果と同じことからReadFIle()は非同期ではなく同期で読み込みをしたのではないか?
と疑問に思っています。
そのため、
・このReadFile()は本当に非同期で動作しているのか?
・ReadFile()が非同期で動いていなければ非同期にするための操作としてどこが間違っているのか?
この点について質問します。
回答して頂くにあたって不足している情報などありましたら教えて下さい。
私のC++のレベルは標準的なC++とstl、その他外部ライブラリを使用することが出来る程度だと思います。
以下のコードで解放部分、ゲッタ部分は省略しています。ファイルハンドルの解放はきちんとCloseHandle()を使っています。
トレースした各関数の戻り値は、
CreateFile() : 正しいファイルハンドル。(INVALID_HANDLE_VALUEではない)
GetFileSize() : 正しいファイルサイズ。
ReadFile() : 0
GetOverlappedResult()の読み込まれたサイズ : GetFileSize()で取得した値と同じ。
GetLastError() : ERROR_IO_PENDING
class AsyncReadFile
{
private:
AsyncReadFile();
private:
OVERLAPPED overlapped;
DWORD fileSize;
DWORD readSize;
void* data;
HANDLE hFile;
public:
static AsyncReadFile* CreateAsyncReadFile( const char* fileName );
bool IsReadCompleted();
void* GetBuffer();
DWORD GetSize();
protected:
void Release();
};
AsyncReadFile::AsyncReadFile() : overlapped()
{
}
AsyncReadFile* AsyncReadFile::CreateAsyncReadFile( const char* fileName )
{
//オブジェクトの作成
AsyncReadFile* ret = new AsyncReadFile;
//ファイルの作成
ret->hFile = CreateFile( fileName, GENERIC_READ, FILE_SHARE_READ , NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL );
if( ret->hFile == INVALID_HANDLE_VALUE ){
//ファイルが開けない
return NULL;
}
ret->fileSize = GetFileSize( ret->hFile, NULL );
ret->data = new unsigned char[ ret->fileSize ];
DWORD rs;
//非同期読み込みの開始
//時間カウント
clock_t c = clock();
BOOL re = ReadFile( ret->hFile, ret->data, ret->fileSize, &ret->readSize, &ret->overlapped );
//時間出力
char out[100];
sprintf_s( out, "time:%d\n", clock()-c );
OutputDebugString( out );
//読み込みサイズの確認(デバッガから確認する)
GetOverlappedResult( ret->hFile, &ret->overlapped, &rs, false );
if( !re ){
if( GetLastError() != ERROR_IO_PENDING ){
//読み込みエラー
CloseHandle( ret->hFile );
return NULL;
}
}
else
{
//呼び出し時点で読み込みが完了している
CloseHandle( ret->hFile );
ret->hFile = INVALID_HANDLE_VALUE;
}
return ret;
}