Skip to content

Instantly share code, notes, and snippets.

@Tocchann
Last active August 3, 2022 13:21
Show Gist options
  • Save Tocchann/da66314cd16c860b8d907a44fd6a9d2f to your computer and use it in GitHub Desktop.
Save Tocchann/da66314cd16c860b8d907a44fd6a9d2f to your computer and use it in GitHub Desktop.
MsgWaitForMultipleObjects の例
#include <map>
#include <functional>
// waitActions に登録する例は載せていない(通常は、排他制御して追加処理するのが良い)
std::map<HANDLE, std::function<bool(bool,bool&)>> waitActions;
DWORD APIENTRY SetupWaitHandles( HANDLE* waitHandles, DWORD capacityCount )
{
DWORD waitCount = 0;
if( capacityCount > 0 )
{
for( const auto& pair : waitActions )
{
if( waitCount >= capacityCount )
{
break;
}
waitHandles[waitCount++] = pair.first;
}
}
return waitCount;
}
bool APIENTRY SignalWaitAction( HANDLE wakeHandle, bool isSucceeded )
{
bool isContinue = true;
auto itr = waitActions.find( wakeHandle );
if( itr != waitActions.end() )
{
if( !itr->second( isSucceeded, isContinue ) )
{
waitActions.erase( itr );
}
}
return isContinue;
}
int RunMessageLoop()
{
HANDLE waitHandles[MAXIMUM_WAIT_OBJECTS-1] ={ nullptr };
// 待機ハンドルをセットアップする。待機ハンドルのセットアップは、この関数を持つクラスで行うことを想定
DWORD waitCount = SetupWaitHandles( waitHandles, MAXIMUM_WAIT_OBJECTS-1 );
bool isContinue = true;
DWORD timeoutTime = 60*1000; // デフォルトは1分ごとにタイムアウト
int resultCode = ERROR_SUCCESS;
do
{
auto result = ::MsgWaitForMultipleObjects( waitCount, waitHandles, FALSE, timeoutTime, QS_ALLINPUT );
// MsgWaitForMultipleObjects のエラー(パラメータが間違っているとかが多い)
if( result == WAIT_FAILED )
{
// エラーコードを見て処理の必要があればそれ相応に処理。ここではプログラム的なバグを想定してそのままリターン
resultCode = ::GetLastError();
isContinue = false;
}
// タイムアウト
else if( result == WAIT_TIMEOUT )
{
// Win32 なので COMを使わないかもしれないけどサンプルとして用意
CoFreeUnusedLibraries();
}
// メッセージが何か来たのでループを回す
else if( result == WAIT_OBJECT_0+waitCount )
{
MSG msg;
while( ::PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
resultCode = static_cast<decltype(resultCode)>(msg.wParam);
isContinue = false;
break;
}
// メッセージの事前処理
// msg.hWnd == nullptr の場合やモードレスダイアログなら IsDialogMessage を呼び出すなどを行う
if( !PreTranslateMessage( &msg ) )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
}
}
// 待機ハンドルがシグナル状態になった(==アクションを起こせ!)
else if( WAIT_OBJECT_0 <= result && result < WAIT_OBJECT_0+waitCount )
{
isContinue = SignalWaitAction( waitHandles[result-WAIT_OBJECT_0], true );
// 継続する場合は毎回整理
if( isContinue )
{
waitCount = SetupWaitHandles( waitHandles, MAXIMUM_WAIT_OBJECTS-1 );
}
}
// 待機に失敗した(Mutexの場合のみ)
else if( WAIT_ABANDONED_0 <= result && result < WAIT_ABANDONED_0+waitCount )
{
isContinue = SignalWaitAction( waitHandles[result-WAIT_ABANDONED_0], false );
// 継続する場合は毎回整理
if( isContinue )
{
waitCount = SetupWaitHandles( waitHandles, MAXIMUM_WAIT_OBJECTS-1 );
}
}
} while( isContinue );
return resultCode;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment