Version 14.29
別スレッドで検索!
「さて、前回のプログラムをたとえば」
iCount = CountMatchFile( "C:\\", "readme.txt" );
「というふうに C ドライブ全体で検索すると、結構時間が掛かると思いま
す」
『しかもその間、アプリ動かない……これがつまり、検索処理してるから、
ウィンドウを操作してもメッセージキューに貯まるだけで何も処理されな
い、って状態なんだね』
「そういうこと。そこで!」
『マルチスレッドの出番!』
「というわけです。でもここから一筋縄ではいかないから」
『う……』
「まず、マルチスレッドは Version 14.14 ( No.281 ) と同じく
_beginthread() を使用します。この時と同じく StdAfx.h にヘッダーを追
加します」
#include <process.h> // 追加。
//{{AFX_INSERT_LOCATION}}
「〈//{{AFX_INSERT_LOCATION}}〉の上に追加してください」
『ほい』
「では使ってみます」
/*
指定したフォルダからファイルを検索します。
戻り値として一致数を返します。
*/
int CountMatchFile
( const char * const p_pchFolderPath
, const char * const p_pchFileName
)
{
int iNum = 0;
// 検索するフォルダをカレントディレクトリにします。
BOOL bRes;
bRes = SetCurrentDirectory( p_pchFolderPath );
if( bRes == FALSE )
{
// フォルダが存在しません。
return -1;
}
CStringArray cFolderStrAry;
// 最初のファイルを取得します。
WIN32_FIND_DATA stWin32FindData;
HANDLE hHandle = NULL;
hHandle = FindFirstFile( "*", &stWin32FindData );
do
{
if( stWin32FindData.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY )
{
// フォルダなので取っておきます。
cFolderStrAry.Add( stWin32FindData.cFileName );
}
else if( _stricmp
( stWin32FindData.cFileName
, p_pchFileName
) == 0 )
{
// ファイル名が一致しました。
++iNum;
}
// 次のファイルを取得します。
}while( FindNextFile( hHandle, &stWin32FindData ) );
// ハンドルを閉じます。
FindClose( hHandle );
// フォルダに対して再帰呼び出しをします。
for( int iF1 = 0; iF1 < cFolderStrAry.GetSize(); ++iF1 )
{
if (
( cFolderStrAry.GetAt( iF1 ) == "." ) ||
( cFolderStrAry.GetAt( iF1 ) == ".." )
)
{
// . と .. はスキップします。
continue;
}
// フォルダを連結します。
CString cPathStr = p_pchFolderPath;
if (
( cPathStr.GetAt
( cPathStr.GetLength() - 1 ) != '\\' ) ||
(
( cPathStr.GetAt
( cPathStr.GetLength() - 1 ) == '\\' ) &&
( _mbsbtype
( (const unsigned char *)(LPCTSTR)cPathStr
, cPathStr.GetLength() - 1
) == 2 )
)
)
{
// 最後に \ がなければくっつけます。
cPathStr += "\\";
}
cPathStr += cFolderStrAry.GetAt( iF1 );
// 再帰呼び出しします。
iNum += CountMatchFile( cPathStr, p_pchFileName );
}
return iNum;
}
void StartCountMatchFile( void *p_p )
{
int iCount = 0;
iCount = CountMatchFile( "C:\\", "readme.txt" );
TRACE( "一致数: %d\n", iCount );
}
void CSearchDlgDlg::OnSearchStart()
{
HANDLE hThread;
hThread
= (HANDLE)_beginthread( StartCountMatchFile, 0, NULL );
// 【検索中】ダイアログを表示します。
CSearchingDlg cDlg;
cDlg.DoModal();
}
『長! って、 CountMatchFile() ってこの前と同じっぽいけど』
「同じなんだけど……ほら、この前プログラム間違えたから、これが正解版
ってことで……」
『あー……』
「というわけで CountMatchFile() の解説は前回と前々回を参照。ここでは
マルチスレッドの部分を解説します。まずは別スレッドで呼び出す部分」
HANDLE hThread;
hThread
= (HANDLE)_beginthread( StartCountMatchFile, 0, NULL );
「 _beginthread() で、別スレッドで StartCountMatchFile() を呼び出し
ます」
void StartCountMatchFile( void *p_p )
{
int iCount = 0;
iCount = CountMatchFile( "C:\\", "readme.txt" );
TRACE( "一致数: %d\n", iCount );
}
『こっちがこの前呼んでた方だね』
「ここは同じ。だから、検索部分そのまままるごと別スレッドで呼び出した
ことになります」
『おー』
「で、それとは別に、メインスレッドではダイアログを表示します」
// 【検索中】ダイアログを表示します。
CSearchingDlg cDlg;
cDlg.DoModal();
『 Version 14.26 ( No.293 ) の時に作ったやつだね』
「これを実行してみて」
『ほい、実行っと。【検索開始】ボタン押して〜おっ、【検索中】ダイアロ
グが出た』
「まだ【キャンセル】ボタンは機能しないけどね」
『う、そうだ……』
「でも押せるでしょ」
『あ、押せるし、ダイアログも動くし』
「これがマルチスレッドの効果」
『そっか、検索は別スレッドだから、メッセージループが止まらないんだ
ね』
「そういうこと。で、少し待つと」
『あ、デバッグウィンドウに一致数出た』
「この流れを図にしてみます」
OnSearchStart() StartCountMatchFile()
呼び出し→→→→→→→→→→→→→→→→→別スレッドで開始
【検索中】ダイアログ表示 検索開始
... (検索中...)
... 検索終了。
(ダイアログを閉じたり StartCountMatchFile() 終了
ウィンドウを動かしたり (スレッドもここで終了)
できます)
【ファイル検索】ダイアログ閉じます。
(アプリケーション終了)
『別々に分かれて、あとでくっつくことはないわけね』
「そういうこと。マルチスレッドの場合、スレッド間の協調が難しいから、
こういうふうに〈処理を投げっぱなしにする〉のが簡単な方法」
『検索処理を投げっぱなしにするわけね』
「そういうこと。でも、実際には協調が必要。今の段階でまだ実装してない
機能は」
・検索対象フォルダの表示
・検索結果の表示
・キャンセル機能
・検索終了時にキャンセルダイアログを閉じる機能
『うわ、かなりある!』
「まだまだ道は険しいからねー」
/*
Preview Next Story!
*/
『でもさでもさ、なんかスレッド使うだけで結構ちゃんとした感じ!』
「こういうのって楽しいでしょ」
『う”、そ、そうだけど……』
「次はもっと楽しくなるよ」
『え!?』
「というわけで次回」
< Version 14.30 スレッドを途中で止める >
『につづく!』
「こうやって機能がどんどん追加できると楽しくなるよー?」
『……なんかあたしのこといじってない?』