Come posso eseguire un semplice bit di codice in una nuova discussione?

Ho un po ‘di codice che ho bisogno di eseguire in un thread diverso rispetto alla GUI in quanto attualmente provoca il blocco del modulo mentre il codice viene eseguito (10 secondi o così).

Supponiamo che non abbia mai creato una nuova discussione prima; che cosa è un semplice esempio di come farlo in C # e utilizzando .NET Framework 2.0 o versioni successive?

Un buon posto per iniziare a leggere è Joe Albahari .

Se vuoi creare il tuo thread, questo è semplice come si ottiene:

using System.Threading; new Thread(() => { Thread.CurrentThread.IsBackground = true; /* run your code here */ Console.WriteLine("Hello, world"); }).Start(); 

BackgroundWorker sembra essere la scelta migliore per te.

Ecco il mio esempio minimo. Dopo aver fatto clic sul pulsante, l’operatore in background inizierà a lavorare nel thread in background e riporterà i suoi progressi contemporaneamente. Riporterà anche dopo il completamento del lavoro.

 using System.ComponentModel; ... private void button1_Click(object sender, EventArgs e) { BackgroundWorker bw = new BackgroundWorker(); // this allows our worker to report progress during work bw.WorkerReportsProgress = true; // what to do in the background thread bw.DoWork += new DoWorkEventHandler( delegate(object o, DoWorkEventArgs args) { BackgroundWorker b = o as BackgroundWorker; // do some simple processing for 10 seconds for (int i = 1; i <= 10; i++) { // report the progress in percent b.ReportProgress(i * 10); Thread.Sleep(1000); } }); // what to do when progress changed (update the progress bar for example) bw.ProgressChanged += new ProgressChangedEventHandler( delegate(object o, ProgressChangedEventArgs args) { label1.Text = string.Format("{0}% Completed", args.ProgressPercentage); }); // what to do when worker completes its task (notify the user) bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler( delegate(object o, RunWorkerCompletedEventArgs args) { label1.Text = "Finished!"; }); bw.RunWorkerAsync(); } 

Nota:

  • Metto tutto in un unico metodo usando il metodo anonimo di C # per semplicità, ma puoi sempre estrapolarli a metodi diversi.
  • È sicuro aggiornare la GUI nei gestori ProgressChanged o RunWorkerCompleted . Tuttavia, l'aggiornamento della GUI da DoWork causerà InvalidOperationException .

ThreadPool.QueueUserWorkItem è ideale per qualcosa di semplice. L’unica avvertenza è accedere a un controllo dall’altro thread.

 System.Threading.ThreadPool.QueueUserWorkItem(delegate { DoSomethingThatDoesntInvolveAControl(); }, null); 

Veloce e sporco, ma funzionerà:

Usando in alto:

 using System.Threading; 

codice semplice:

 static void Main( string[] args ) { Thread t = new Thread( NewThread ); t.Start(); } static void NewThread() { //code goes here } 

Ho appena gettato questo in una nuova applicazione console per un exmaple

Ecco un’altra opzione:

 Task.Run(()=>{ //Here is a new thread }); 

Prova a utilizzare la class BackgroundWorker . Gli dai dei delegati per ciò che devono essere eseguiti e per essere avvisato quando il lavoro è finito. C’è un esempio sulla pagina MSDN a cui mi sono collegato.

Se vuoi ottenere un valore:

 var someValue; Thread thread = new Thread(delegate() { //Do somthing and set your value someValue = "Hello World"; }); thread.Start(); while (thread.IsAlive) Application.DoEvents(); 

Metti il ​​codice in una funzione (il codice che non può essere eseguito sullo stesso thread della GUI) e per triggersre l’esecuzione di quel codice, inserisci quanto segue.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

Chiamando la funzione di avvio sull’object thread si causerà l’esecuzione della chiamata di funzione in una nuova discussione.

Ecco come usare i thread con progressBar, è solo per capire come funzionano i thread, nella forma ci sono tre progressBar e 4 pulsanti:

  public partial class Form1 : Form { public Form1() { InitializeComponent(); } Thread t, t2, t3; private void Form1_Load(object sender, EventArgs e) { CheckForIllegalCrossThreadCalls = false; t = new Thread(birinicBar); //evry thread workes with a new progressBar t2 = new Thread(ikinciBar); t3 = new Thread(ucuncuBar); } public void birinicBar() //to make progressBar work { for (int i = 0; i < 100; i++) { progressBar1.Value++; Thread.Sleep(100); // this progressBar gonna work faster } } public void ikinciBar() { for (int i = 0; i < 100; i++) { progressBar2.Value++; Thread.Sleep(200); } } public void ucuncuBar() { for (int i = 0; i < 100; i++) { progressBar3.Value++; Thread.Sleep(300); } } private void button1_Click(object sender, EventArgs e) //that button to start the threads { t.Start(); t2.Start(); t3.Start(); } private void button4_Click(object sender, EventArgs e)//that button to stup the threads with the progressBar { t.Suspend(); t2.Suspend(); t3.Suspend(); } private void button2_Click(object sender, EventArgs e)// that is for contuniue after stuping { t.Resume(); t2.Resume(); t3.Resume(); } private void button3_Click(object sender, EventArgs e) // finally with that button you can remove all of the threads { t.Abort(); t2.Abort(); t3.Abort(); } } 
 // following declaration of delegate ,,, public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, DateTime procDateTime); // following inside of some client method GetEnergyUsageDelegate nrgDel = GetEnergyUsage; IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null); while (!aR.IsCompleted) Thread.Sleep(500); int usageCnt = nrgDel.EndInvoke(aR); 

Charles il tuo codice (sopra) non è corretto. Non hai bisogno di girare aspettare il completamento. EndInvoke bloccherà fino a quando non viene segnalato WaitHandle.

Se si desidera bloccare fino al completamento è semplicemente necessario

 nrgDel.EndInvoke(nrgDel.BeginInvoke(lastRuntime,procDT,null,null)); 

o in alternativa

 ar.AsyncWaitHandle.WaitOne(); 

Ma qual è il punto di emissione di eventuali chiamate se blocchi? Potresti anche usare una chiamata sincrona. Una scommessa migliore sarebbe quella di non bloccare e passare in un lambda per la pulizia:

 nrgDel.BeginInvoke(lastRuntime,procDT,(ar)=> {ar.EndInvoke(ar);},null); 

Una cosa da tenere a mente è che devi chiamare EndInvoke. Un sacco di persone dimenticano questo e finiscono col lasciare WaitHandle mentre le implementazioni più asincrone rilasciano il waithip in EndInvoke.

Se si intende utilizzare l’object Raw Thread, è necessario impostare IsBackground su true al minimo e impostare anche il modello Threading Apartment (probabilmente STA).

 public static void DoWork() { // do some work } public static void StartWorker() { Thread worker = new Thread(DoWork); worker.IsBackground = true; worker.SetApartmentState(System.Threading.ApartmentState.STA); worker.Start() } 

Raccomando la class BackgroundWorker se hai bisogno dell’interazione dell’interfaccia utente.

un’altra opzione, che utilizza i delegati e il pool di thread …

assumendo ‘GetEnergyUsage’ è un metodo che prende un DateTime e un altro DateTime come argomenti di input, e restituisce un Int …

 // following declaration of delegate ,,, public delegate long GetEnergyUsageDelegate(DateTime lastRunTime, DateTime procDateTime); // following inside of some client method GetEnergyUsageDelegate nrgDel = GetEnergyUsage; IAsyncResult aR = nrgDel.BeginInvoke(lastRunTime, procDT, null, null); while (!aR.IsCompleted) Thread.Sleep(500); int usageCnt = nrgDel.EndInvoke(aR); 

Esistono molti modi per eseguire thread separati in .Net, ognuno ha comportamenti diversi. È necessario continuare a eseguire il thread dopo la chiusura della GUI? Hai bisogno di passare le informazioni tra il thread e la GUI? Il thread deve aggiornare la GUI? Se il thread esegue un’attività, allora si chiude, o dovrebbe continuare a funzionare? Le risposte a queste domande ti diranno quale metodo usare.

Esiste un buon articolo sul metodo asincrono nel sito Web di Code Project che descrive i vari metodi e fornisce un codice di esempio.

Nota che questo articolo è stato scritto prima del pattern async / await e Task Parallel Library è stato introdotto in .NET.

Procedura: utilizzare una discussione in background per cercare file

Devi essere molto attento con l’accesso da altri thread a cose specifiche della GUI (è comune per molti toolkit della GUI). Se vuoi aggiornare qualcosa nella GUI dall’elaborazione del thread, controlla questa risposta che penso sia utile per WinForms. Per WPF vedere questo (mostra come toccare componente nel metodo UpdateProgress () in modo che funzioni da altri thread, ma in realtà non mi piace che non CheckAccess() facendo CheckAccess() prima di fare BeginInvoke tramite Dispathcer, vedere e cercare CheckAccess in esso)

Stavo cercando il libro specifico di .NET sul threading e ho trovato questo (scaricabile gratuitamente). Vedi http://www.albahari.com/threading/ per maggiori dettagli a riguardo.

Credo che troverai ciò di cui hai bisogno per avviare l’esecuzione come nuovo thread nelle prime 20 pagine e ne ha molte altre (non sono sicuro di frammenti specifici della GUI, intendo strettamente specifico del threading). Sarei felice di sentire cosa pensa la comunità di questo lavoro perché sto leggendo questo. Per ora mi è sembrato abbastanza carino (per mostrare metodi e tipi specifici di .NET per il threading). Inoltre copre .NET 2.0 (e non antica 1.1) ciò che apprezzo davvero.

Consiglierei di guardare la libreria di threading di Jeff Richter e in particolare l’IAsyncEnumerator. Dai un’occhiata al video sul blog di Charlie Calvert in cui Richter lo esamina per una buona panoramica.

Non lasciatevi scoraggiare dal nome perché rende più semplici le attività di programmazione asincrona.