Processus.HasExited retourne true même si process est en cours d'exécution?

j'ai pu observer que Process.HasExited retourne parfois true même si le processus est toujours en cours d'exécution.

Mon code ci-dessous démarre un processus avec le nom "testprogram.exe" et puis attend à la sortie. Le problème est que parfois j'ai jeté l'exception; il semble que, même si HasExited retourne true le processus lui-même est encore en vie dans le système - comment cela peut-il être??

mon programme écrit dans un fichier journal juste avant qu'il ne se termine et j'ai donc besoin de assurez-vous absolument que ce fichier journal existe (alias le processus a pris fin/terminé) avant de le lire. Continuellement vérifier son existence n'est pas une option.

// Create new process object
process = new Process();

// Setup event handlers
process.EnableRaisingEvents = true;
process.OutputDataReceived += OutputDataReceivedEvent;
process.ErrorDataReceived += ErrorDataReceivedEvent;
process.Exited += ProgramExitedEvent;

// Setup start info
ProcessStartInfo psi = new ProcessStartInfo
                           {
                               FileName = ExePath,
                               // Must be false to redirect IO
                               UseShellExecute = false,
                               RedirectStandardOutput = true,
                               RedirectStandardError = true,
                               Arguments = arguments
                           };

process.StartInfo = psi;

// Start the program
process.Start();

while (!process.HasExited)
    Thread.Sleep( 500 );

Process[] p = Process.GetProcessesByName( "testprogram" );

if ( p.Length != 0 )
    throw new Exception("Oh oh");

mise à JOUR: j'ai juste essayé d'attente avec process.WaitForExit() au lieu de la boucle de sondage et le résultat est exactement le même.

Ajout: le code ci-dessus était seulement pour démontrer un problème "plus clair" de la même façon. Pour être clair, mon problème N'est pas que je puisse encore mettre la main sur le processus par Process.GetProcessesByName( "testprogram" ); après avoir mis HasExited pour vrai.

le vrai problème est que le programme que j'exécute extérieurement écrit un fichier-juste avant - il se termine (gracieusement). J'utilise HasExited à vérifier quand le processus est terminé et donc je sais que je peux lire le fichier (parce que le processus est sorti!), mais il semble que HasExited retourne true même parfois quand le programme n'a pas encore écrit le fichier sur le disque. Voici un exemple de code qui illustre le problème:

// Start the program
process.Start();

while (!process.HasExited)
    Thread.Sleep( 500 );
// Could also be process.WaitForExit(), makes no difference to the result

// Now the process has quit, I can read the file it has exported
if ( !File.Exists( xmlFile ) )
{
    // But this exception is thrown occasionally, why?
    throw new Exception("xml file not found");
}
28
demandé sur sharptooth 2010-03-26 00:52:20

11 réponses

je me rends compte que c'est un vieux post, mais dans ma quête pour savoir pourquoi mon application dirigeant l'événement quitté avant même l'application avait ouvert j'ai découvert quelque chose que je bien que pourrait être utile aux personnes éprouvant ce problème dans le futur.

Lorsqu'un processus est lancé, on lui assigne un PID. si L'utilisateur est alors invité avec la boîte de dialogue Contrôle du compte de l'Utilisateur et sélectionne 'Oui', le processus est redémarré et un nouveau PID lui est assigné.

je me suis assis avec cela pendant quelques heures, espérons que cela peut sauver quelqu'un moment.

11
répondu Dave 2016-01-15 16:47:42

je vous suggère d'essayer de cette façon:

process.Start();

while (!process.HasExited)
{
    // Discard cached information about the process.
    process.Refresh();

    // Just a little check!
    Console.WriteLine("Physical Memory Usage: " + process.WorkingSet64.ToString());

    Thread.Sleep(500);
}

foreach (Process current in Process.GetProcessesByName("testprogram"))
{
    if ((current.Id == process.Id) && !current.HasExited)
        throw new Exception("Oh oh!");
}

de toute façon... dans la page MSDN de hasexited n', je suis en train de lire la suite mise en évidence remarque:

lorsque la sortie standard a été redirigée vers un événement asynchrone handlers, il est possible que le traitement de sortie n'ait pas terminé lorsque cette propriété retourne true. Pour s'assurer que asynchrone la gestion de l'événement est terminée, appelez la surcharge de WaitForExit() cela ne prend aucun paramètre avant de vérifier HasExited.

cela pourrait être en quelque sorte lié à votre problème que vous redirigez tout.

6
répondu Tommaso Belluzzo 2013-01-15 16:06:02

tout d'Abord, êtes-vous sûr testprogram ne produit pas un processus de ses propres et sortir sans attendre que ce processus pour finir? Nous avons affaire à une sorte de condition de race ici, et le programme de test peut être important.

le deuxième point que je voudrais faire est à ce sujet - "je dois être absolument sûr que ce logfile existe". Eh bien, il n'y a pas une telle chose. Vous pouvez faire votre chèque, et puis le dossier est parti. La façon commune de traiter ceci n'est pas de vérifier, mais plutôt de faire ce que vous voulez faire avec le fichier. Allez-y, lisez-le, saisissez les exceptions, réessayez si la chose semble instable et que vous ne voulez rien changer. Le check-and-do fonctionnel ne fonctionne pas bien si vous avez plus d'un acteur (thread ou autre) dans le système.

un tas d'idées au hasard suit.

avez-vous essayé D'utiliser FileSystemWatcher et ne dépend pas de l'achèvement du processus?

T-il faire mieux si vous essayez de lire le fichier (pas vérifier s'il existe, mais jouer à la place) dans le processus.Sorti de l'événement? [il ne devrait pas]

le système Est-il en bonne santé? Quelque chose de suspect dans le Registre?

est-ce vraiment agressif antivirus politique-ils être impliqués?

(on ne peut pas dire grand chose sans voir tout le code et regarder dans le programme de test.)

4
répondu Mikhail 2013-01-17 21:46:13

je sais, c'est un vieux post, mais peut-être que je peux aider quelqu'un.

la classe Process peut se comporter de manière inattendue! HasExited renvoie true si le processus a quitté ou si le processus s'exécute avec des privilèges d'administrateur et votre programme, a privilèges de l'utilisateur.

4
répondu Michael Plainer 2018-07-25 09:28:51

alors juste pour une enquête plus approfondie sur la cause profonde du problème, vous devriez peut-être vérifier ce qui se passe réellement en utilisant Moniteur De Processus. Tout simplement commencer à y inclure le programme externe et votre propre outil et le laisser enregistrer ce qui se passe.

dans le log, vous devriez voir comment l'outil externe écrit dans le fichier de sortie et comment vous ouvrez ce fichier. Mais à l'intérieur de ce journal, vous devriez voir dans quel ordre tous ces accès se produisent.

La première chose qui est venu à mon esprit, c'est que l' Process la classe ne ment pas et le processus est vraiment parti quand il le dit. Donc, le problème est qu'à ce moment, il semble que le fichier n'est pas encore entièrement disponibles. Je pense que c'est un problème de l'OS, parce qu'il contient encore certaines parties du fichier dans un cache qui n'est pas entièrement écrit sur le disque et que l'outil s'est tout simplement sorti sans vider ses poignées de fichier.

Avec cela à l'esprit, vous devriez voir dans le journal que l'outil externe a créé le fichier, est sorti et après cela le fichier sera vidé/fermé (par L'OS [peut-être supprimer tous les filtres quand vous avez trouvé ce point dans le journal]).

donc si mes suppositions sont correctes la cause racine serait le mauvais comportement de votre outil externe que vous ne pouvez pas changer conduisant ainsi à simplement attendre un peu après le processus a quitté et espérer que le délai est assez long pour obtenir le fichier rincé/fermé par L'OS (peut-être essayer d'ouvrir le fichier dans un boucle avec un temps mort jusqu'à ce qu'il ait réussi).

3
répondu Oliver 2013-01-16 12:36:15

pour commencer, y a-t-il un problème avec l'utilisation du processus.WaitForExit plutôt que de sonder?

quoi qu'il en soit, il est techniquement possible pour le processus de sortir d'un point de vue utilisable, mais le processus est encore autour brièvement alors qu'il fait des choses comme cache de disque flush. Est-ce que le fichier journal est particulièrement grand (ou toute opération qu'il exécute lourd sur les Écritures de disque)?

1
répondu tyranid 2010-03-25 21:56:16

Il y a deux possibilités, l'objet process continue de contenir une référence au processus, donc il est sorti, mais il n'a pas encore été supprimé. Ou vous avez une deuxième instance du processus en cours. Vous devriez également comparer L'Id du processus pour vous assurer. Essayez ceci.

    ....

    // Start the program
    process.Start();


    while (!process.HasExited)
        Thread.Sleep( 500 );

    Process[] p = Process.GetProcessesByName( "testprogram" );
    if ( p.Length != 0 && p[0].Id == process.id && ! p[0].HasExited)
        throw new Exception("Oh oh");
1
répondu John Knoeller 2010-03-25 21:59:44

selon MSDN documentationHasExited.

si une poignée est ouverte au processus, les versions du système d'exploitation à l' mémoire de processus lorsque le processus a a quitté, mais reste administratif des informations sur le processus, tels que la poignée, le code de sortie et l'Heure de sortie.

probablement pas lié, mais cela vaut la peine de noter.

Si c'est seulement un problème 1/10 du temps, et le processus disparaît après un deuxième quoi qu'il en soit, en fonction de votre usage de HasExited, essayez juste d'ajouter un autre délai après que le contrôle HasExited fonctionne, comme

while (!process.HasExited)
    DoStuff();
Thread.Sleep(500);
Cleanup();

et voir si le problème persiste.

Personnellement, j'ai toujours utilisé le Exited event handler au lieu de n'importe quel type de sondage, et un emballage personnalisé simpliste autour de System.Diagnostics.Process pour gérer des choses comme la sécurité du fil, envelopper un appel à CloseMainWindow() suivi de WaitForExit(timeout) et enfin Kill(), l'exploitation forestière, et cetera, et jamais rencontré un problème.

1
répondu Tanzelax 2010-03-25 22:40:24

peut-être que le problème est dans le programme de test? Est-ce que ce code chasse d'eau/fermer, etc.? Il me semble que si testprogram écrit un fichier sur disque, le fichier devrait au moins être disponible (vide ou pas)

1
répondu Roy 2010-04-29 08:27:52

si vous avez une application web, et que votre programme/processus externe génère des fichiers (écriture sur disque) vérifiez si votre IIS a le droit d'écrire dans ce dossier si ce n'est pas sur la sécurité des propriétés ajoutez la permission pour votre utilisateur IIS, c'était la raison dans mon cas, je recevais le processus.HasExited =true, mais les fichiers produits à partir du processus n'a pas été achevé, après avoir lutté pendant un certain temps, j'Ajoute les permissions complètes dans le dossier où le processus était writhing et le processus.Rafraîchir() comme Zarathos décrit de ci-dessus et tout fonctionnait comme prévu.

0
répondu No Name 2014-04-18 00:16:48

Utiliser process_name.Refresh() avant de vérifier si le processus est terminé ou non. Refresh() va effacer toute l'information mise en cache liée au processus.

-1
répondu Mohammad Shakir 2015-04-30 09:11:49