(C++)ReadFile関数が非同期読み込みになっていない?

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
sdr

(C++)ReadFile関数が非同期読み込みになっていない?

#1

投稿記事 by sdr » 11年前

環境:Microsoft Visual Studio 2010
言語: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;
}

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: (C++)ReadFile関数が非同期読み込みになっていない?

#2

投稿記事 by へにっくす » 11年前

えーと肝心の
OVERLAPPED overlapped;
をゼロクリアしてるところはどこですか。

C/C++言語は、明示的に初期化しない限り、どんな値が入ってるか分かりませんので注意してください。
Win32API(C言語)編 第52章 非同期的なファイルの読み書き
written by へにっくす

adr

Re: (C++)ReadFile関数が非同期読み込みになっていない?

#3

投稿記事 by adr » 11年前

返信ありがとうございます。

>えーと肝心の
>OVERLAPPED overlapped;
>をゼロクリアしてるところはどこですか。

overlappedの初期化につきましては、コード25行目のAsyncReadFileクラスのコンストラクタの初期化子として、
overlapped構造体のコンストラクタを呼び出す形でゼロクリアしています。
デバッガでもクリアされていることを確認しています。

アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: (C++)ReadFile関数が非同期読み込みになっていない?

#4

投稿記事 by へにっくす » 11年前

adr さんが書きました:コード25行目のAsyncReadFileクラスのコンストラクタの初期化子として
なるほど了解です。

こちらでも試してみましたが同じような現象でしたね。
ReadFileExではどうでしょう?こちらは非同期専用らしいです。
ReadFileEx関数 - MSDN
オフトピック
ReadFile一つで済むなら、ふつうわざわざReadFileExなんて作らないと思うので、
非同期でReadFileを使うのはやめた方がいいのかも・・・とか思ったり
written by へにっくす

sdr

Re: (C++)ReadFile関数が非同期読み込みになっていない?

#5

投稿記事 by sdr » 11年前

コード52行目を以下のように変更しましたが、やはり数百ms待たされ改善したように見えませんでした・・・
ううむ、何が悪いのか・・・ それとも非同期でこれなのか。

戻り値に対応するために62行目以降を実験的に取り去りました。

コード:

BOOL re = ReadFileEx( ret->hFile, ret->data, ret->fileSize, &ret->overlapped, NULL ); 


アバター
へにっくす
記事: 634
登録日時: 13年前
住所: 東京都

Re: (C++)ReadFile関数が非同期読み込みになっていない?

#7

投稿記事 by へにっくす » 11年前

考えたら、ファイルサイズを読込サイズに指定してるので、結局1回で読むことになる、ということでない?
とか思ったけど違うのだろうか…

あとこんなのもあった。。
SDK32:NT の非同期ディスク I/O は同期のように見える
written by へにっくす

閉鎖

“C言語何でも質問掲示板” へ戻る