当进程结束时,您可以使用RegisterWaitForSingleObject() 通过回调获得通知。 RegisterWaitForSingleObject 函数指示thread pool 中的等待线程等待进程,因此这应该是资源的最佳使用。正如 Raymond Chen 所说:
线程池可以将多个等待请求批处理到一个调用中
WaitForMultipleObjects 所以摊销成本是线程的 1/63。
下面是一个 Win32 GUI 应用程序的最小示例。代码创建一个窗口,然后创建另一个自身实例作为子进程,由“/child”参数指示。它注册等待回调函数并运行常规消息循环。您可以调整窗口大小并移动窗口以查看 GUI 是否未被阻止。当子进程结束时,系统异步调用等待回调,该回调将应用程序定义的消息(WM_APP)发布到窗口。窗口收到消息后,立即调用UnregisterWait()取消等待。如参考所述,即使是使用 WT_EXECUTEONLYONCE 的等待操作也必须在等待完成时取消(但不能从回调中取消!)。然后窗口显示一个消息框,表明它已收到消息。
为简洁起见,省略了错误处理。您应该检查每个 API 函数的返回值,并在返回 FALSE 时调用 GetLastError()。
#pragma comment(linker, "/SubSystem:Windows")
#include <windows.h>
#include <string>
int APIENTRY wWinMain( HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPWSTR lpCmdLine, int /*nCmdShow*/ )
{
if ( wcsstr( lpCmdLine, L"/child" ) )
{
MessageBoxW( nullptr, L"Hello from child process!", L"Child", MB_OK );
return 0;
}
// Create window
struct WindowData
{
HANDLE hWait = nullptr;
}
wndData;
WNDCLASSW wc{};
wc.hInstance = hInstance;
wc.hCursor = LoadCursor( nullptr, IDC_ARROW );
wc.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject( WHITE_BRUSH ));
wc.lpszClassName = L"MyClass";
wc.cbWndExtra = sizeof(LONG_PTR);
wc.lpfnWndProc = []( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_APP:
{
// When the wait is completed, you must call the UnregisterWait or UnregisterWaitEx function to cancel
// the wait operation. (Even wait operations that use WT_EXECUTEONLYONCE must be canceled.)
WindowData* pWndData = reinterpret_cast<WindowData*>(GetWindowLongPtr( hWnd, 0 ));
UnregisterWait( pWndData->hWait );
pWndData->hWait = nullptr;
MessageBoxW( hWnd, L"Child process has ended!", L"Main", MB_OK );
}
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
}
return DefWindowProc( hWnd, message, wParam, lParam );
};
RegisterClassW( &wc );
HWND hWnd = CreateWindowExW( 0, wc.lpszClassName, L"Main", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr );
SetWindowLongPtr( hWnd, 0, reinterpret_cast<LONG_PTR>( &wndData) );
// Create child process
std::wstring cmd( MAX_PATH, L'\0' );
cmd.resize( GetModuleFileNameW( nullptr, &cmd[0], cmd.size() ) );
cmd = L"\"" + cmd + L"\" /child";
STARTUPINFOW si{ sizeof( si ) };
PROCESS_INFORMATION pi{};
CreateProcessW( nullptr, &cmd[0], nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi );
// Get notified when child process ends
RegisterWaitForSingleObject( &wndData.hWait, pi.hProcess,
[]( PVOID lpParameter, BOOLEAN /*TimerOrWaitFired*/ )
{
PostMessage( reinterpret_cast<HWND>(lpParameter), WM_APP, 0, 0 );
},
reinterpret_cast<PVOID>(hWnd), INFINITE, WT_EXECUTEONLYONCE );
// Run message loop
MSG msg;
while ( GetMessage( &msg, nullptr, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
// Cleanup
if( wndData.hWait )
UnregisterWait( wndData.hWait );
if( pi.hProcess )
CloseHandle( pi.hProcess );
if( pi.hThread )
CloseHandle( pi.hThread );
return 0;
}
Bonus OldNewThing read:Why bother with RegisterWaitForSingleObject when you have MsgWaitForMultipleObjects?