2009-10-29 3 views
2

Tout le monde connaît le code pour exécuter un programme et d'attendre à la fin:CreateProcess avec la dégradation des performances WaitForSingleObject

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

Il a été utilisé à plusieurs reprises par moi-même. Mais récemment, j'ai trouvé que cet appel quand il lance un programme avec une lecture multimédia a des performances moins bonnes que le même processus en cours d'exécution à partir d'un gestionnaire de fichiers général (Windows XP). C'est correct avec la consommation CPU de mon processus (parent), mais pendant la lecture du fragment, il y a de petits arrêts inattendus.

J'ai fait un peu de changement à quelque chose comme:

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

Et cela a aidé. Maintenant, le processus enfant joue le fragment sans problèmes. Alors, quel est le problème avec le premier fragment et est-il documenté quelque part? Comme je le vois à partir des tests, la deuxième "attente" est plus "détendue" que la première, mais la première ne mange pas CPU au moins formellement

Répondre

3

Si ce code est exécuté sur un thread d'interface utilisateur, vous provoquerez problèmes de performances avec d'autres processus qui envoient (directement ou indirectement) des messages à vos fenêtres, puisque vous n'exécutez pas la boucle de message pendant que vous attendez le processus fils. Ni Sleep() ni WaitForSingleObject() ne traiteront les messages.

Explorateur Windows (le gestionnaire de fichiers) ne souffrira pas ce problème car:

  1. ne garde pas une poignée ouverte aux processus, il lance à la demande de l'utilisateur (je pense que cela est plus probable, puisque les besoins Explorateur Ne pas savoir quand le processus se termine ou son code de sortie), ou
  2. N'attend pas sur aucun processus ouvert les poignées qu'il peut garder de ses enfants, et surtout
  3. Toujours s'assure d'exécuter une boucle de message pendant qu'il attend des poignées . Ceci est très important dans tout processus utilisant COM, que l'explorateur utilise fortement.

Au lieu d'appeler WaitForSingleObject(), vous pouvez appeler MsgWaitForMultipleObjects(). Si vous spécifiez QS_ALLINPUT pour le paramètre dwWaitMask, MsgWaitForMultipleObjects sera renvoyé lorsque votre événement est signalé ou lorsqu'il y a une entrée dans la file d'attente des messages du thread. Si MsgWaitForMultipleObjects() est renvoyé car un message est disponible, vous pouvez le traiter et reprendre l'attente:

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

Vous regardez du mauvais côté. Apparemment, le processus enfant a une performance pire si le parent est bloqué en attente. WTF en effet. – MSalters

+1

Légère buglet dans cette réponse: le lien pointé par 'MsgWaitForMultipleObjects()' pointe vers la documentation MSDN de la fonction Sleep(). Un peu drôle en quelque sorte. ;-) –

Questions connexes