Processus asynchrone démarrer et attendre la fin

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

  1. démarre un processus qui gère un fichier (processus.StartInfo.Nom_fichier = nom_fichier;)
  2. Attendez que l'utilisateur ferme le processus ou abandonne le thread après un certain temps
  3. si l'utilisateur a fermé le processus, supprimer le fichier

Le démarrage du processus et l'attente doivent être effectués sur un thread différent du thread principal, car cette opération ne doit pas affecter l'application.

Exemple:

Mon application produit un rapport html. L'utilisateur peut faire un clic droit quelque part et dire "afficher le rapport" - maintenant, je récupère le contenu du rapport dans un fichier temporaire et lance le processus qui gère les fichiers html, c'est-à-dire le navigateur par défaut. Le problème est que je ne peux pas nettoyer, c'est-à-dire supprimer le fichier temporaire.

35
demandé sur Bogdan Gavril MSFT 2009-03-04 18:35:17

5 réponses

"et l'attente doit être asynchrone" - Je n'essaie pas d'être drôle, mais n'est-ce pas une contradiction en termes? Cependant, puisque vous démarrez 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, peut-être juste utiliser un thread différent?

ThreadPool.QueueUserWorkItem(delegate {
    Process process = Process.Start(startInfo);
    if(process.WaitForExit(timeout)) {
        // user exited
    } else {
        // timeout
    }
});
60
répondu Marc Gravell 2015-11-11 17:16:14

Ajout d'une alternative avancée à cette ancienne question. Si vous voulez attendre la sortie d'un processus sans bloquer aucun thread et prendre en charge les délais d'attente, 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 la surcharge de votre application.

18
répondu Chris Gillum 2013-07-30 00:39:50

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
}
4
répondu JaredPar 2009-03-04 15:45:30

Je n'utiliserais probablement pas un processus séparé pour ouvrir un fichier. Au lieu de cela, j'utiliserais probablement un thread d'arrière-plan (si je pensais que l'opération allait prendre beaucoup de temps et bloquer possible le thread de L'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 de L'interface utilisateur). Mais cette approche est généralement la façon dont je gestion des opérations asynchrones dans. Net.

0
répondu Chris Holmes 2009-03-04 15:46:27

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

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é

0
répondu Pablo Retyk 2009-03-04 15:50:36