並列ライブラリを利用する
マルチスレッド版にしたことでメッセージ処理が滞ることがなくなり、ユーザー操作のレスポンスが今までと違い格段によくなっていることが分かると思います。ここまで来ると、気になるのがCPU利用率です。ここまでのプログラムはアクティブに処理する部分が1つしかないため、結果的にCPUパワーは1つ分しか利用していません(サンプルプログラムはグラフに分かりやすく出るようにわざと、CPUの利用を1か所に寄せています)。現在は多くのマシンが2~4個のCPUコアを持っています。時間のかかる処理も、複数のコアで同時に行うようにすれば、全力で作業できます。
Visual Studio 2010では、同時実行ライブラリの中のPPL(Parallel Pattern Library:並列パターンライブラリ)に、ループを並列化するなどさまざまな並列化ルーチンが用意されています。今回はこの中から、parallel_forというforループを並列化するロジックを利用してマルチコアで全力で作業するようにしてみました。また、分かりやすいようにダイアログを出している間の時間を計測して、どの程度で処理が終わっているかも分かるようにしてあります。
void _cdecl BusyLoopThProcDlgPPL( void* param )
{
CThreadParamDlg* pParam = static_cast( param );
int nSec = pParam->m_workTime/1000;
Concurrency::parallel_for( 0, nSec, []( int ){
DWORD dwStart = GetTickCount();
while( (GetTickCount()-dwStart) < 1000 );
});
// 端数はおまけ処理として扱う(サンプルではここは通らない)
DWORD restTime = pParam->m_workTime%1000;
if( restTime != 0 ){
DWORD dwStart = GetTickCount();
while( (GetTickCount()-dwStart) < restTime );
}
PostMessage( pParam->m_hwndDlg, WM_COMMAND, MAKEWPARAM( IDOK, 0 ), 0 ); // 処理終了はOKメニュー風に通知
}
INT_PTR CALLBACK DlgProc_PPL(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch( message ){
case WM_INITDIALOG:
{
CSimpleWaitCursor wait;
CThreadParamDlg* pParam = reinterpret_cast( lParam );
pParam->m_hwndDlg = hDlg;
Concurrency::CurrentScheduler::ScheduleTask( BusyLoopThProcDlgPPL, pParam );
}
return TRUE;
case WM_COMMAND:
if( LOWORD(wParam) == IDOK ){
EndDialog( hDlg, LOWORD(wParam) );
return TRUE;
}
break;
}
return FALSE;
}
void ThreadBusyLoopModalPPL( HWND hwnd, DWORD dwTime )
{
DWORD dwStart = GetTickCount();
{
CThreadParamDlg param( dwTime );
DialogBoxParam( hInst, MAKEINTRESOURCE(IDD_WAIT), hwnd, DlgProc_PPL, reinterpret_cast<LPARAM>( ¶m ) );
}
DWORD dwEnd = GetTickCount();
TCHAR szBuff[256];
wsprintf( szBuff, _T("経過時間:%u.%03u 秒"), (dwEnd-dwStart)/1000, (dwEnd-dwStart)%1000 );
MessageBox( hwnd, szBuff, _T("WaitSample"), MB_OK );
}
サンプルは30秒処理するようにしてあります。手元の開発環境が8コアだったので計測したところ、4~5秒程度で終了していました。8等分より少し時間がかかっていますが、スレッド切り替えのオーバーヘッドを考慮すれば、処理時間としては悪くないと思われます。
おわりに
前編、後編にわたって、いくつかの「処理中」を表現する方法を紹介してきました。これですべてではありませんが、基本となる部分は一通り網羅していると思います。マルチスレッドも安易に利用できるようなものではありませんが、ハードウェアの能力を最大限活用するためには、避けては通れない時代になっています。CodeZineにもマルチスレッド(並列処理)の記事がたくさんあるので、参考にしていただければと思います。
