2011-10-13 16 views
5

Ho un'applicazione console C# che crea fino a 5 thread.Applicazione console multi-thread C# - La console si chiude prima dei thread completi

I thread si stanno eseguendo correttamente, ma il thread dell'interfaccia utente si arresta non appena termina il suo lavoro.

C'è un modo per mantenere attivo il thread principale dell'interfaccia utente, per tutto il tempo in cui i thread laterali sono in esecuzione?

foreach (var url in urls) 
{ 
    Console.WriteLine("starting thread: " + url); 
    ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(myMethod), url); 
} 

Sto lanciando i miei thread come da codice sopra.

+0

Cosa succede se hai creato thread normali, invece di utilizzare il threadpool? –

+6

Quale versione di .NET? Se .NET 4.0 raccomando le attività TPL, memorizza tutte le attività in un array e usa Tasks.WaitAll (myTaskArray) prima di uscire. –

+0

Penso che i thread debbano essere 'BackgroundWorker = false' – IAbstract

risposta

6

Se si utilizza .NET 4.0:

var tasks = new List<Task>(); 

foreach(var url in urls) 
{ 
    tasks.Add(Task.Factory.StartNew(myMethod, url)); 
} 

// do other stuff... 

// On shutdown, give yourself X number of seconds to wait for them to complete... 
Task.WaitAll(tasks.ToArray(), TimeSpan.FromSeconds(30)); 
+3

Parallel.ForEach() fa tutto questo in 1 piccola riga ... –

2

Ah - ThreadPool è sullo sfondo. È in coda, ma il tuo programma finisce. Finito. Il programma termina.

Leggere su Semaphores (WaitSignal) e attendere- I thread nella richiamata al segnale di fine sono terminati, quando tutti hanno segnalato che il thread principale può continuare.

8

I thread nel ThreadPool sono thread in background e ciò significa che un'applicazione in uscita non attenderà il completamento.

avete alcune opzioni:

  • attesa con ad esempio un semaforo
  • attesa su un contatore con il sonno(), molto rozzi ma male per una semplice console app.
  • usare il TPL, Parallel.ForEach(urls, url => MyMethod(url));
+1

+1 per 'Parallel.ForEach (urls, url => MyMethod (url))'. –

+0

+1, ma non consiglierei il contatore + Sonno per niente .. vale anche la pena notare che si può usare un 'CountDownEvent'. – Kiril

+0

@Lirik Il CountDownEv è Fx4 +, quindi potresti usare TPL. –

0

più semplice hack per risolvere il problema.

Nella classe programma:

static volatile int ThreadsComplete = 0; 

Nel vostro "myMethod" alla fine prima di ritorno:

//ThreadsComplete++; //*edit* for safety's sake 
Interlocked.Increment(ref ThreadsComplete); 

nel metodo principale prima che ritorni/finisce:

while(ThreadsComplete < urls.Count) { Thread.Sleep(10); } 

Quanto sopra essenzialmente unisce insieme un metodo di sincronizzazione WaitForAll.

+0

Questa è una buona soluzione, facile da implementare, grazie. –

+2

Non è una buona soluzione. È un hack facile da usare. –

+1

Ecco perché hai un 'CountdownEvent' ... non è necessario il loop o il sonno, il che è comunque una cattiva pratica per l'attesa. – Kiril

-1

nel Main:

var m = new ManualResetEvent(false); 
// do something 
foreach (var url in urls) 
{ 
    Console.WriteLine("starting thread: " + url); 
    ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(myMethod), url); 
} 
m.WaitOne(); 


private static void myMethod(object obj) 
{ 
    try{ 
    // do smt 
    } 
    finally { 
    m.Set(); 
    } 
} 
+0

Questo codice non garantisce l'attesa di ** tutti ** i thread. –

+0

Se cambia 'ManualResetEvent' in' CountDownEvent', questa sarà una buona soluzione. – Kiril

+0

@Lirik Con abbastanza modifiche, potrebbe scrivere anche un poema –

0

Se stai usando .net 4 poi:

urls.AsParallel().ForAll(MyMethod); 

Prima di NET 4 quindi avviare i singoli thread, tenerli in un elenco e chiamare Join (). Il fatto che i lavoratori non siano in background li terrebbe vivi dopo che il thread principale è terminato, ma Join() è più esplicito.

 List<Thread> workers = new List<Thread>(); 
     foreach(var url in urls) 
     { 
      Thread t = new Thread(MyMethod) {IsBackground = false}; 
      workers.Add(t); 
      t.Start(url); 
     } 

     foreach (var worker in workers) 
     { 
      worker.Join(); 
     } 
Problemi correlati