CreateProcess 与 WaitForSingleObject 性能下降

发布于 2024-08-09 14:03:57 字数 512 浏览 3 评论 0原文

每个人可能都知道运行程序并等待其结束的代码:

   CreateProcess(...
   WaitForSingleObject(Process.hProcess, INFINITE

我自己使用过几次。但最近我发现,当它启动具有多媒体播放功能的程序时,此调用的性能比从通用文件管理器(Windows XP)执行的相同进程差。我的(父)进程的 CPU 消耗没问题,但在播放片段时会出现意外的小停顿。

我做了一些改变,比如:

CreateProcess ...
do {
    Sleep(100);
    Res = WaitForSingleObject(Process.hProcess, 10);
} while (Res == WAIT_TIMEOUT);

这有帮助。现在子进程播放该片段没有问题。 那么第一个片段有什么问题,它是否记录在某处?正如我从测试中看到的,第二个“等待”比第一个“等待”更“放松”,但第一个至少在形式上不会占用 CPU

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情魔剑神 2024-08-16 14:03:57

如果此代码在 UI 线程上运行,则会导致其他(直接或间接)向窗口发送消息的进程出现性能问题,因为在等待子进程时不会运行消息循环。 Sleep()WaitForSingleObject() 将处理消息。

Windows 资源管理器(文件管理器)不会遇到此问题,因为它:

  1. 不保留打开的句柄来处理它根据用户请求启动的进程(我认为这更有可能,因为资源管理器不需要知道进程何时退出或其退出代码),或者
  2. 不等待它可能从其子级保留的任何打开的进程句柄,重要的是
  3. 始终确保在等待句柄时运行消息循环。这对于任何使用 COM 的进程都非常重要,因为 Explorer 大量使用 COM。

您可以调用 MsgWaitForMultipleObjects(),而不是调用 WaitForSingleObject() 。如果您为 dwWaitMask 参数指定 QS_ALLINPUT,则当您的事件发出信号或线程的消息队列中有输入时,MsgWaitForMultipleObjects 将返回。如果 MsgWaitForMultipleObjects() 由于消息可用而返回,您可以处理它并继续等待:

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;
    }
}

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:

  1. Does not keep an open handle to processes it launches at the user's request (I think this is more likely, since Explorer needs neither to know when the process exits or its exit code), or
  2. Does not wait on any open process handles it may keep from its children, and importantly
  3. Always makes sure to run a message loop while it waits on handles. This is very important in any process that makes use of COM, which Explorer uses heavily.

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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文