2009-12-17 6 views
3

J'écris un programme C# qui lancera de nombreux processus enfants. À un moment ultérieur, j'aurai besoin de récupérer ces processus par ID et de faire correspondre ces processus à un ensemble de processus stockés dans un dictionnaire qui ont été ajoutés au dictionnaire lors de leur création initiale. Cependant, je suis en cours d'exécution dans un problème qui semble être pur ... ridiculeFrustration .NET - Process.GetProcessById renvoie une nouvelle référence

Process notepad = new Process(); 
notepad.StartInfo.FileName = "notepad"; 
notepad.Start(); 

Process n2 = Process.GetProcessById(notepad.Id); 

Debug.WriteLine(notepad == n2);  //'False', but Why isn't this true??? 
Debug.WriteLine(notepad.Id == n2.Id); //'True' 

Je l'ai utilisé réflecteur .NET pour savoir que GetProcessById retourne un « nouveau processus (...) », mais semble devoir juste trouver une référence au processus déjà en cours et le renvoyer à la place.

Vous pouvez supposer la première instruction de débogage est essentiellement un appel comme

données MyCustomDataType = MyDictionary [bloc-notes];

Je m'attendrais à obtenir les données que j'ai insérées à l'origine, à la place je reçois une KeyNotFoundException probablement parce que le comparateur par défaut effectue une vérification de référence. Pour contrer cela, j'ai ajouté un IComparer personnalisé sur mon dictionnaire qui vérifie juste que les deux objets Process ont le même ID, donc je peux obtenir les données associées comme prévu. Cependant, cela a son propre problème en ce que les processus qui ne sont pas en cours d'exécution n'ont pas d'ID de processus, donc parfois l'appel dans mon IComparer personnalisé à Process.ID lève une exception InvalidOperationException !!! Donc, j'ai résolu un problème seulement pour en créer un autre.

Donc, je suppose que j'ai deux questions:

  • Pourquoi ne retourne .NET pas seulement une référence à une instance de processus déjà en cours?
  • Que puis-je faire pour faire correspondre les processus stockés dans mon dictionnaire, car l'ID de processus n'est pas toujours valide pour la durée de vie de l'objet Processus?

Répondre

2

Les programmes en cours d'exécution sont des processus du système d'exploitation et non des instances du type géré par processus. Le type Process est un type d'objet wrapper géré autour d'un concept de système d'exploitation. Il permet de contrôler le processus cible en masquant les appels P/Invoke. Le système d'exploitation ne nécessite pas qu'une instance particulière de la classe Process effectue ces opérations, ce qui explique pourquoi GetProcessById peut renvoyer une nouvelle instance tout en continuant à attendre que tout fonctionne.

L'ID est valide pour la durée du processus lui-même. Peut-être que vous pouvez définir EnableRaisingEvents à true et ajouter un gestionnaire d'événements à l'événement Process.Exited qui supprime le processus de votre cache?

2

Que voudriez-vous .net faire, dans ce cas?

1er Executable

Process notepad = new Process(); 
notepad.StartInfo.FileName = "notepad"; 
notepad.Start(); 

On suppose que vous connaissez le processId de l'instance bloc-notes.
Dans le 2ème exécutable, vous voulez mettre la main sur ce processus en utilisant l'identifiant

2ème Executable

Process n2 = Process.GetProcessById(notepadIdInputByUser); 

comparaison de référence objet peut être effectué dans une application, à condition que la construction de l'objet est dans la main (par rapport au système d'exploitation).

Comment .net vous obtiendra l'instance de Process du 1er exécutable dans le 2ème exécutable?

EDIT: Bien que Process soit une classe, elle ne peut pas être comparée.
Il agit comme un struct, où vous pourriez faire la comparaison de membre.

2

1) Votre première question est analogue à:

var a = new List<string>{"one", "two", "three"}; 
var b = new List<string>{"one", "two", "three"}; 

if(a == b) { Debug.WriteLine("awesome"); } // not going to happen 

Rien n'est de garder la trace créé List<string> 's qui est la même pour créer Process Je vous suggère de ne pas s

2) Process dans le dictionnaire et créer une autre classe qui stocke l'ID du processus et les références Process et fait quelque chose d'intelligent lorsque le processus que le Process se réfère à ne fonctionne plus.

5

Pas vraiment sûr pourquoi vous avez dû recourir à réflecteur, car la GetProcessByID documentation MSDN indique clairement:

Crée un nouveau composant de processus et associe à la ressource de processus existant que vous spécifiez.

Le cadre ne peut pas vous renvoyer la même instance que vous avez. Pour être en mesure de faire cela, le framework devrait garder une référence à toutes les instances de processus jamais créées et comparer l'identifiant de processus pour les découvrir. Je vais vous laisser imaginer les implications que cela aurait sur la mémoire et la performance du framework. En outre, la classe Process est un wrapper autour du handle de processus renvoyé par l'API Win32 OpenProcess. Et il est possible d'avoir plusieurs poignées dans le même processus. Et la redirection d'entrée/sortie peut être effectuée sur une base par poignée, ainsi, il est prévu scénario de pouvoir avoir deux instances de processus qui représentent le même processus et l'un d'entre eux traitant des flux de sortie et d'erreur et l'autre avec le flux d'entrée.

Sur une note séparée, il me semble que vous utilisez l'objet Process lui-même comme clé pour le dictionnaire. Mais l'objet Process ne représente pas l'identité du processus réel, il est juste une représentation du processus. Vous devriez utiliser comme clé quelque chose qui représente l'identité du processus à la place.

+0

Bonjour Franci. Merci beaucoup pour votre explication claire. Que recommanderiez-vous pour «utiliser comme clé quelque chose qui représente l'identité du processus à la place»? Je ne peux pas vraiment penser à une propriété en construction en plus de l'ID. De plus, j'ai besoin de la propriété pour vivre toute la vie de l'objet Process, que le processus soit en cours ou non. – Chad

+0

l'ID de processus est la représentation de l'identité du processus. :-) Donc, votre clé devrait être l'identifiant du processus. bien sûr, vous voulez évidemment garder l'objet Process associé à celui-ci plus quelques données supplémentaires que vous conservez dans votre dictionnaire actuel. Vous avez des options - soit étendre les données que vous gardez dans le dictionnaire avec l'objet Process et le mettre en clé par l'ID, soit ajouter un second dictionnaire où vous gardez les objets Processus entrés par ID. –

+1

Les ID de processus (PID) ne sont pas une bonne représentation de l'identité du processus. Si un processus se termine, l'OS est libre de réutiliser le même PID pour un nouveau processus plus tard. Un Tuple de l'ID du processus et l'heure à laquelle le processus a commencé (pour traiter le cas du recyclage PID) est une bien meilleure identité. –

0

Utilisez ProcessId comme clé de votre dictionnaire. N'ayez pas peur de créer une nouvelle instance de Process en utilisant GetProcessById à chaque fois que vous en avez besoin. C'est un objet léger et le ramasse-miettes va nettoyer pour vous.