Reputation: 2401
Everyone probably knows the code to run a program and wait for it to end:
CreateProcess(...
WaitForSingleObject(Process.hProcess, INFINITE
It was used several times by myself. But recently I found that this call when it launches a program with a multimedia playback has worse performance than the same process being executed from a general file manager (Windows XP). That's ok with CPU consumption of my (parent) process, but while playing the fragment there are unexpected little stops.
I made a little change to something like:
CreateProcess ...
do {
Sleep(100);
Res = WaitForSingleObject(Process.hProcess, 10);
} while (Res == WAIT_TIMEOUT);
And it helped. Now the child process plays the fragment without problems. So what's wrong with the first fragment and is it documented somewhere? As I see from the tests the second "wait" is more "relaxed" than the first one, but the first one doesn't eat CPU at least formally
Upvotes: 2
Views: 6150
Reputation: 2128
If this code is running on a UI thread, you will cause performance problems with other processes that (directly or indirectly) send messages to your window(s), since you do not run the message loop while you are waiting for the child process. Neither Sleep() nor WaitForSingleObject() will process messages.
Windows Explorer (the file manager) will not suffer this problem because it:
Instead of calling WaitForSingleObject(), you can call MsgWaitForMultipleObjects(). If you specifiy QS_ALLINPUT for the dwWaitMask parameter, MsgWaitForMultipleObjects will return either when your event is signaled or when there is input in the thread's message queue. If MsgWaitForMultipleObjects() returned because a message is available, you can process it and resume waiting:
MSG msg;
DWORD reason = WAIT_TIMEOUT;
while (WAIT_OBJECT_0 != reason) {
reason = MsgWaitForMultipleObjects(1, &hChildProcess, FALSE, INFINITE, QS_ALLINPUT);
switch (reason) {
case WAIT_OBJECT_0:
// Your child process is finished.
break;
case (WAIT_OBJECT_0 + 1):
// A message is available in the message queue.
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
// Note that if your main message loop does additional processing
// (such as calling IsDialogMessage() for modeless dialogs)
// you will want to do those things here, too.
}
break;
}
}
Upvotes: 2