38 votes

Le processus asynchrone démarre et attend qu'il se termine

Je suis nouveau sur le modèle de thread dans .net. Que voulez-vous utiliser pour:

  1. le début d'un processus qui gère un fichier (le processus.StartInfo.FileName = nom de fichier;)
  2. d'attente pour l'utilisateur de fermer le processus OU d'abandonner le fil après un certain temps
  3. si l'utilisateur a fermé le processus, supprimer le fichier

Le démarrage du processus et d'attente doit être faite sur un autre thread que le thread principal, parce que cette opération ne devrait pas affecter l'application.

Exemple:

Mon application produit un rapport html. L'utilisateur peut clic droit quelque part et dire "Afficher le Rapport" - maintenant, j'ai récupérer le contenu du rapport dans un fichier temporaire et de lancer le processus qui gère les fichiers html, c'est à dire le navigateur par défaut. Le problème est que je ne peut pas le nettoyage, c'est à dire supprimer les fichiers temporaires.

61voto

Marc Gravell Points 482669

"et attendre doit être asynchrone" - je n'essaie pas d'être drôle, mais n'est-ce pas une contradiction en termes? Cependant, puisque vous lancez un Process , l'événement Exited peut aider:

         ProcessStartInfo startInfo = null;
        Process process = Process.Start(startInfo);
        process.EnableRaisingEvents = true;
        process.Exited += delegate {/* clean up*/};
 

Si vous voulez réellement attendre (timeout, etc.), alors:

 if(process.WaitForExit(timeout)) {
    // user exited
} else {
    // timeout (perhaps process.Kill();)
}
 

Pour attendre async, utilisez peut-être simplement un thread différent?

         ThreadPool.QueueUserWorkItem(delegate {
            Process process = Process.Start(startInfo);
            if(process.WaitForExit(timeout)) {
                // user exited
            } else {
                // timeout
            }
        });
 

23voto

Chris Gillum Points 3782

Ajout d'une alternative avancée à cette ancienne question. Si vous souhaitez attendre la fin d'un processus sans bloquer aucun thread et toujours prendre en charge les délais d'expiration, essayez ce qui suit:

     public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
    {
        ManualResetEvent processWaitObject = new ManualResetEvent(false);
        processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

        RegisteredWaitHandle registeredProcessWaitHandle = null;
        registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
            processWaitObject,
            delegate(object state, bool timedOut)
            {
                if (!timedOut)
                {
                    registeredProcessWaitHandle.Unregister(null);
                }

                processWaitObject.Dispose();
                tcs.SetResult(!timedOut);
            },
            null /* state */,
            timeout,
            true /* executeOnlyOnce */);

        return tcs.Task;
    }
 

Encore une fois, l'avantage de cette approche par rapport à la réponse acceptée est que vous ne bloquez aucun thread, ce qui réduit les frais généraux de votre application.

3voto

JaredPar Points 333733

Essayez le code suivant.

 public void KickOffProcess(string filePath) {
  var proc = Process.Start(filePath);
  ThreadPool.QueueUserWorkItem(new WaitCallBack(WaitForProc), proc);
}

private void WaitForProc(object obj) {
  var proc = (Process)obj;
  proc.WaitForExit();
  // Do the file deletion here
}
 

0voto

Chris Holmes Points 5475

Je n'aurais probablement pas l'utilisation d'un processus distinct pour l'ouverture d'un fichier. Au lieu de cela, je serais probablement utiliser un thread d'arrière-plan (si je pensais que l'opération allait prendre du temps et possible de bloquer le thread d'INTERFACE utilisateur).

private delegate void FileOpenDelegate(string filename);

public void OpenFile(string filename)
{
   FileOpenDelegate fileOpenDelegate = OpenFileAsync;
   AsyncCallback callback = AsyncCompleteMethod;
   fileOpenDelegate.BeginInvoke(filename, callback, state);
}

private void OpenFileAsync(string filename)
{
   // file opening code here, and then do whatever with the file
}

Bien sûr, ce n'est pas un bon exemple de travail (il ne renvoie rien) et je n'ai pas montré comment l'INTERFACE utilisateur est mise à jour (vous devez utiliser BeginInvoke au niveau de l'INTERFACE utilisateur, car un thread d'arrière-plan ne peut pas mettre à jour le thread d'INTERFACE utilisateur). Mais cette approche est généralement la façon dont je vais sur la gestion des opérations asynchrones dans .Net.

0voto

pablito Points 2905

Vous pouvez utiliser l'événement Exited dans la classe Process

 ProcessStartInfo info = new ProcessStartInfo();

info.FileName = "notepad.exe";
Process process = Process.Start(info);

process.Exited += new EventHandler(process_Exited);
Console.Read();
 

et dans ce cas, vous pouvez gérer les opérations que vous avez mentionnées

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X