2010-03-01 8 views
16

Vorrei iniziare x numero di thread dalla mia applicazione .NET, e vorrei tenerne traccia poiché dovrò terminarli manualmente o quando la mia applicazione chiude la mia domanda più tardi.Avvio di più thread e tracciamento di essi dalla mia applicazione .NET

Esempio ==> Inizia Discussione Alpha, Beta Inizia Discussione .. poi in qualsiasi punto della mia domanda dovrei essere in grado di dire Terminate Beta Discussione ..

Qual è il modo migliore per tenere traccia di discussioni aperte in .NET e cosa devo sapere (un ID?) su un thread per terminarlo? Codice di esempio, tutorial sarebbe utile.

risposta

14

si potrebbe risparmiare il lavoro asino e utilizzare questa Smart Thread Pool. Fornisce un'unità di sistema di lavoro che consente di interrogare lo stato di ogni thread in qualsiasi punto e di terminarli.

Se questo è troppo disturbo, allora come già detto uno IDictionary<string,Thread> è probabilmente la soluzione più semplice.O ancora più semplice è dare a ciascuno di tuo thread un nome, e utilizzare un IList<Thread>:

public class MyThreadPool 
{ 
    private IList<Thread> _threads; 
    private readonly int MAX_THREADS = 25; 

    public MyThreadPool() 
    { 
     _threads = new List<Thread>(); 
    } 

    public void LaunchThreads() 
    { 
     for (int i = 0; i < MAX_THREADS;i++) 
     { 
      Thread thread = new Thread(ThreadEntry); 
      thread.IsBackground = true; 
      thread.Name = string.Format("MyThread{0}",i); 

      _threads.Add(thread); 
      thread.Start(); 
     } 
    } 

    public void KillThread(int index) 
    { 
     string id = string.Format("MyThread{0}",index); 
     foreach (Thread thread in _threads) 
     { 
      if (thread.Name == id) 
       thread.Abort(); 
     } 
    } 

    void ThreadEntry() 
    { 

    } 
} 

Ovviamente si può ottenere molto di più coinvolti e complicato con esso. Se uccidere i tuoi thread non è sensibile al fattore tempo (ad esempio se non hai bisogno di uccidere un thread in 3 secondi in un'interfaccia utente), un Thread.Join() è una pratica migliore.

E se non l'hai ancora letto, Jon Skeet ha this good discussion and solution per il consiglio "non utilizzare abort" che è comune su SO.

+0

Ho una domanda, sul Void ThreadEntry(), una volta creato un multiplo di thread nell'applicazione principale del punto di partenza del thread, possiamo lanciare qualsiasi altra applicazione su quel thread in base al numero di thread che hai assegnato. – shawn

1

dipende da quanto sofisticato è necessario che sia. È possibile implementare il proprio tipo di ThreadPool con metodi di supporto ecc. Tuttavia, ritengo che sia semplice come mantenere una lista/array e aggiungere/rimuovere i thread da/alla raccolta di conseguenza.

Si potrebbe anche usare una collezione Dizionario e utilizzare il proprio tipo di chiave particolare per recuperarli ossia GUID/stringhe.

2

Dopo aver creato il thread, è possibile impostare la proprietà Name. Supponendo di memorizzare in qualche collezione è possibile accedervi comodamente tramite LINQ al fine di recuperare (e abortire) è:

var myThread = (select thread from threads where thread.Name equals "myThread").FirstOrDefault(); 
if(myThread != null) 
    myThread.Abort(); 
1

Wow, ci sono così tante risposte ..

  1. Si può semplicemente utilizzare una matrice per tenere i fili, questo sistema funziona solo se l'accesso alla matrice sarà sequantial, ma se avrete un altro thread l'accesso a questo array, sarà necessario sincronizzare l'accesso
  2. È possibile utilizzare il pool di thread, ma il pool di thread è molto limitato e può contenere solo una quantità fissa di thread.
  3. Come accennato in precedenza, è possibile creare voi proprio pool di thread, che in .NET v4 diventa molto più facile con l'introduzione di collezioni sicure.
  4. è possibile gestirli tenendo una lista di oggetti mutex che determinerà quando quei fili dovrebbero finire, i fili interrogherà il mutex ogni volta che corrono prima di fare qualsiasi altra cosa, e se il suo set, terminare, è possibile gestire le sordine da qualsiasi luogo, e dal momento che sono mutex da defenition thread-safe, la sua abbastanza facile ..

posso pensare di altri 10 modi, ma quelli sembra funzionare. fammi sapere se non si adattano alle tue esigenze.

3

È possibile creare un dizionario di fili e assegnare loro id, come:

Dictionary<string, Thread> threads = new Dictionary<string, Thread>(); 
for(int i = 0 ;i < numOfThreads;i++) 
{ 
    Thread thread = new Thread(new ThreadStart(MethodToExe)); 
    thread.Name = threadName; //Any name you want to assign 
    thread.Start(); //If you wish to start them straight away and call MethodToExe 
    threads.Add(id, thread); 
} 

Se non si desidera salvare le discussioni contro un Id è possibile utilizzare una lista e in seguito solo enumerare per uccidere filettature.

E quando desideri interromperli, puoi annullarli. Meglio avere alcune condizioni nel tuo MethodToExe che consente a quel metodo di lasciare che il thread termini con grazia. Qualcosa di simile:

void MethodToExe() 
{ 
    while(_isRunning) 
    { 
     //you code here// 
     if(!_isRunning) 
     { 
      break; 
     } 
     //you code here// 
    } 
} 

di abortire è possibile enumerare il dizionario e chiamare Thread.Abort().Siate pronti a catturare ThreadAbortException

+0

@ cornerback84 Vorrei sconsigliare l'uso di Thread.Abort() ... è meglio impostare il thread su sfondo. – Kiril

+0

Sì, ma stavo semplicemente mostrando come farlo. Ecco perché gli ho suggerito di avere qualche condizione in cui possa interrompere il thread. Può essere questo, o qualsiasi eccezione come SocketException a cui si può uscire dal metodo – ata

3

ho chiesto a una serie di domande simili e ha ricevuto un sacco di buone risposte: Shutting down a multithreaded application

Nota: la mia domanda non ha richiesto un'uscita elegante, ma la gente ancora raccomandato che ho con grazia l'uscita dal ciclo di ogni filo.

La cosa più importante da ricordare è che se si vuole evitare di avere le discussioni che impediscono il processo di terminare è necessario impostare tutte le vostre discussioni a sfondo:

Thread thread = new Thread(new ThreadStart(testObject.RunLoop)); 
thread.IsBackground = true; 
thread.start(); 

Il modo migliore per avviare e gestire thread è in a ThreadPool, ma quasi tutti i contenitori là fuori possono essere utilizzati per mantenere un riferimento ai thread. I tuoi thread dovrebbero sempre avere un flag che indichi loro di terminare e dovrebbero controllarlo continuamente.

Inoltre, per un migliore controllo è possibile fornire le discussioni che con un CountdownLatch: ogni volta che un filo sta uscendo proprio circuito segnalerà su un CountdownLatch. Il thread principale chiamerà il metodo CountdownLatch.Wait() e bloccherà fino a quando tutti i thread non avranno segnalato ... questo ti permetterà di pulire correttamente e assicurerà che tutti i tuoi thread si siano arrestati prima di iniziare a ripulire.

public class CountdownLatch 
{ 
    private int m_remain; 
    private EventWaitHandle m_event; 

    public CountdownLatch(int count) 
    { 
     Reset(count); 
    } 

    public void Reset(int count) 
    { 
     if (count < 0) 
      throw new ArgumentOutOfRangeException(); 
     m_remain = count; 
     m_event = new ManualResetEvent(false); 
     if (m_remain == 0) 
     { 
      m_event.Set(); 
     } 
    } 

    public void Signal() 
    { 
     // The last thread to signal also sets the event. 
     if (Interlocked.Decrement(ref m_remain) == 0) 
      m_event.Set(); 
    } 

    public void Wait() 
    { 
     m_event.WaitOne(); 
    } 
} 

E 'anche degno di ricordare che il metodo Thread.Abort() fa alcune cose strane:

Quando un thread chiama Interruzione su se stessa, l'effetto è simile a un'eccezione ; la ThreadAbortException si verifica immediatamente e il risultato è prevedibile. Tuttavia, se un thread chiama Abort su un altro thread, l'interruzione interrompe qualsiasi codice sia in esecuzione. C'è anche la possibilità che un costruttore statico possa essere interrotto. In casi rari, questo potrebbe impedire alle istanze di di quella classe di essere create nel dominio dell'applicazione. In le versioni .NET Framework 1.0 e 1.1, è possibile che il thread si interrompa mentre un blocco finally è in esecuzione, nel qual caso il blocco finally viene interrotto.

Il filo che chiama interruzione potrebbe blocco se il filo che viene interrotta è in una zona protetta di codice, ad esempio un blocco catch, infine blocco, o vincolata regione esecuzione . Se il thread che chiama Interrompi contiene un blocco che richiede il thread interrotto , si può verificare un deadlock.

1

All'avvio di ogni thread, posizionare il suo ManagedThreadId in un dizionario come chiave e l'istanza del thread come valore. Utilizzare una richiamata da ciascun thread per restituire il suo ManagedThreadId, che è possibile utilizzare per rimuovere il thread dal dizionario quando termina. Puoi anche camminare sul dizionario per interrompere i thread, se necessario. Trasforma i thread in background in modo che vengano interrotti se l'app termina in modo imprevisto.

È possibile utilizzare un callback separato per segnalare i thread per continuare o interrompere, che riflette un flag impostato dall'interfaccia utente, per un'uscita graduale. Dovresti anche intercettare ThreadAbortException nei tuoi thread in modo che tu possa fare qualsiasi pulizia se invece devi interrompere i thread.

Problemi correlati