wake-up-neo.com

Async-Prozess starten und warten, bis der Vorgang abgeschlossen ist

Ich bin neu im Thread-Modell in .net. Was würdest du benutzen: 

  1. einen Prozess starten, der eine Datei behandelt (process.StartInfo.FileName = Dateiname;)
  2. warten Sie, bis der Benutzer den Prozess beendet OR den Thread nach einiger Zeit beendet
  3. wenn der Benutzer den Prozess geschlossen hat, löschen Sie die Datei

Das Starten des Prozesses und das Warten sollten in einem anderen Thread als dem Hauptthread ausgeführt werden, da dieser Vorgang die Anwendung nicht beeinträchtigen sollte.

Beispiel: 

Meine Anwendung erstellt einen HTML-Bericht. Der Benutzer kann irgendwo mit der rechten Maustaste klicken und "Bericht anzeigen" sagen. Jetzt rufe ich den Berichtsinhalt in einer temporären Datei ab und starte den Prozess, der HTML-Dateien verarbeitet, d. H. Den Standardbrowser. Das Problem ist, dass ich nicht bereinigen kann, d. H. Die temporäre Datei löschen kann.

36

"und Warten muss asynchron sein" - Ich versuche nicht, lustig zu sein, aber ist das nicht ein Widerspruch? Da Sie jedoch eine Process starten, kann das Exited-Ereignis hilfreich sein:

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

Wenn Sie tatsächlich warten möchten (Timeout usw.), dann:

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

Verwenden Sie für das Warten async vielleicht nur einen anderen Thread?

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

Hinzufügen einer fortgeschrittenen Alternative zu dieser alten Frage. Wenn Sie auf das Beenden eines Prozesses warten möchten, ohne einen Thread zu blockieren und trotzdem Zeitlimits unterstützen, versuchen Sie Folgendes:

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

Der Vorteil dieses Ansatzes gegenüber der akzeptierten Antwort ist wiederum, dass Sie keine Threads blockieren, wodurch der Aufwand Ihrer App reduziert wird.

18
Chris Gillum

Versuchen Sie den folgenden Code. 

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
JaredPar

Ich würde wahrscheinlich keinen separaten Prozess zum Öffnen einer Datei verwenden. Stattdessen würde ich wahrscheinlich einen Hintergrund-Thread verwenden (wenn ich dachte, die Operation würde lange dauern und den UI-Thread möglicherweise blockieren). 

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
}

Natürlich ist dies kein gutes Arbeitsbeispiel (es gibt nichts zurück) und ich habe nicht gezeigt, wie die Benutzeroberfläche aktualisiert wird (Sie müssen BeginInvoke auf der Benutzeroberflächenebene verwenden, da ein Hintergrund-Thread den Benutzeroberflächen-Thread nicht aktualisieren kann). Mit diesem Ansatz gehe ich jedoch in der Regel mit asynchronen Vorgängen in .Net um. 

0
Chris Holmes

Sie können das Ereignis Exited in der Prozessklasse verwenden

ProcessStartInfo info = new ProcessStartInfo();

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

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

in diesem Fall können Sie die von Ihnen erwähnten Operationen ausführen

0
Pablo Retyk