2009-03-04 26 views
32

Sono nuovo al modello di thread in .net. Che cosa usereste per:Il processo asincrono ha inizio e aspetta che finisca

  1. avviare un processo che gestisce un file (process.StartInfo.FileName = filename;)
  2. attesa per l'utente di chiudere il processo o abbandonare il filo dopo qualche tempo
  3. se l'utente ha chiuso il processo, elimina il file

L'avvio del processo e l'attesa dovrebbero essere eseguiti su un thread diverso rispetto al thread principale, poiché questa operazione non dovrebbe influire sull'applicazione.

Esempio:

La mia applicazione produce un report HTML. L'utente può fare clic con il tasto destro del mouse da qualche parte e dire "Visualizza report" - ora recupererò il contenuto del report in un file temporaneo e avvierò il processo che gestisce i file html, ovvero il browser predefinito. Il problema è che non riesco a ripulire, ad esempio eliminare il file temporaneo.

+0

Console ap o WinForms o ASP.NET? – Richard

+0

Console o WinForms.Il processo che sto avviando è locale alla macchina. –

+0

Ho un esempio che usa async/await postato qui-- http://www.allampersandall.com/2013/03/net-process-async-await – Micah

risposta

58

"e l'attesa deve essere asincrona" - Non sto cercando di essere divertente, ma non è una contraddizione in termini? Tuttavia, dal momento che si avvia un Process, l'evento Exited può aiutare:

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

Se si vuole aspettare in realtà (timeout, ecc), allora:

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

Per asincrona in attesa, forse, basta usare un thread diverso?

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

Ho una domanda. Se ho una funzione A() {ThreadPool.UnsafeQueueUserWorkItem ((o) => { .... proc.WaitForExit(); ...} e nel metodo principale che ho in questo modo: A(); Console.Write ("aa"); ad esempio ... la cosa è quando console.write termina il suo lavoro e il thread non ha ancora finito il suo lavoro .. la pagina si sta caricando e non sta aspettando il processo per termine Cosa devo fare? Grazie ragazzi – Grace

+0

@Grace difficile da dire basato solo su quello ... ma a meno che tu * aspetti * per il thread di lavoro, non è esattamente quello che ti aspetteresti * di vedere? –

+0

così io dovrebbe aspettare che il thread termini dal metodo principale? – Grace

4

Provare il seguente codice.

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 
} 
+1

Non è sicuro che gestisca "O abbandonare il thread dopo un po 'di tempo" –

0

Probabilmente non utilizzerei un processo separato per aprire un file. Invece, probabilmente utilizzerei un thread in background (se pensassi che l'operazione avrebbe richiesto molto tempo e possibile bloccare il thread dell'interfaccia utente).

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 
} 

Naturalmente, questo non è un buon esempio di lavoro (restituisce niente) e non ho mostrato come l'interfaccia utente viene aggiornata (è necessario utilizzare BeginInvoke a livello di interfaccia utente perché un thread in background non può aggiornare il Thread dell'interfaccia utente). Ma questo approccio è in generale il modo in cui gestisco le operazioni asincrone in .Net.

+0

Scusa, in realtà intendevo che il processo doveva gestire il file, non aprirlo. Ho riscritto la domanda. –

0

È possibile utilizzare l'evento Exited in classe Process

ProcessStartInfo info = new ProcessStartInfo(); 

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

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

e in tal caso è possibile gestire le operazioni che hai menzionato

+0

questo non è asincrono –

17

Aggiunta di un'alternativa avanzata per questa vecchia domanda. Se si desidera attendere per un processo per uscire senza bloccare qualsiasi filo e ancora sostenere timeout, provare quanto segue:

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

Anche in questo caso, il vantaggio di questo approccio rispetto alla risposta accettata è che non sei il blocco alcun thread, che riduce il sovraccarico della tua app.

Problemi correlati