¿Cómo ejecuto un simple código en un nuevo hilo?

Tengo un poco de código que necesito ejecutar en un hilo diferente que la GUI, ya que actualmente hace que el formulario se congele mientras el código se ejecuta (10 segundos más o menos).

Supongamos que nunca he creado un nuevo hilo antes; ¿Qué es un ejemplo simple / básico de cómo hacer esto en C # y usar .NET Framework 2.0 o posterior?

Un buen lugar para comenzar a leer es Joe Albahari .

Si desea crear su propio hilo, esto es lo más simple posible:

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

BackgroundWorker parece ser la mejor opción para ti.

Aquí está mi ejemplo mínimo. Después de hacer clic en el botón, el trabajador de fondo comenzará a trabajar en el hilo de fondo y también informará su progreso simultáneamente. También informará después de que el trabajo se complete.

 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:

  • Puse todo en un solo método usando el método anónimo de C # para simplificar, pero siempre puedes sacarlos a diferentes métodos.
  • Es seguro actualizar la GUI dentro de los manejadores ProgressChanged o RunWorkerCompleted . Sin embargo, la actualización de GUI de DoWork causará InvalidOperationException .

El ThreadPool.QueueUserWorkItem es bastante ideal para algo simple. La única advertencia es acceder a un control desde el otro hilo.

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

Rápido y sucio, pero funcionará:

Usando en la parte superior:

 using System.Threading; 

código simple:

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

Acabo de lanzar esto en una nueva aplicación de consola para un exmaple

Aquí hay otra opción:

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

Intenta usar la clase BackgroundWorker . Le da a los delegates qué ejecutar y que se les avise cuando el trabajo haya terminado. Hay un ejemplo en la página MSDN a la que me he vinculado.

Si quieres obtener un valor:

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

Ponga ese código en una función (el código que no se puede ejecutar en el mismo hilo que la GUI), y para activar la ejecución de ese código ponga lo siguiente.

Thread myThread= new Thread(nameOfFunction);

workerThread.Start();

Llamar a la función de inicio en el objeto de hilo provocará la ejecución de su llamada de función en un nuevo hilo.

Aquí, ¿cómo se pueden usar los hilos con una barra de progreso? Solo sirve para entender cómo funcionan los hilos, en la forma hay tres botones progressBar y 4:

  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 su código (arriba) no es correcto. No es necesario girar para esperar a que termine. EndInvoke se bloqueará hasta que se indique WaitHandle.

Si quiere bloquear hasta completarlo, simplemente necesita

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

o alternativamente

 ar.AsyncWaitHandle.WaitOne(); 

¿Pero cuál es el punto de emitir llamadas anyc si bloquea? También podría usar una llamada síncrona. Una mejor apuesta sería no bloquear y pasar una lambda para la limpieza:

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

Una cosa a tener en cuenta es que debe llamar a EndInvoke. Mucha gente olvida esto y termina filtrando el WaitHandle, ya que la mayoría de las implementaciones asincrónicas lanzan el indicador de espera en EndInvoke.

Si vas a utilizar el objeto Thread crudo, entonces debes establecer IsBackground en verdadero como mínimo y también debes establecer el modelo Threading Apartment (probablemente 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() } 

Recomendaría la clase BackgroundWorker si necesita interacción UI.

otra opción, que usa delegates y el grupo de subprocesos …

suponiendo que ‘GetEnergyUsage’ es un método que toma un DateTime y otro DateTime como argumentos de entrada, y devuelve 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); 

Hay muchas maneras de ejecutar hilos separados en .Net, cada uno tiene diferentes comportamientos. ¿Necesita continuar ejecutando el hilo después de que se cierre la GUI? ¿Necesita pasar información entre el hilo y la GUI? ¿El hilo necesita actualizar la GUI? Si el hilo hace una tarea, salga, o debería continuar ejecutándose? Las respuestas a estas preguntas le dirán qué método usar.

Hay un buen artículo de método asíncrono en el sitio web de Code Project que describe los diversos métodos y proporciona código de muestra.

Tenga en cuenta que este artículo se escribió antes de que se introdujera el patrón async / await y Task Parallel Library en .NET.

Cómo: utilizar un hilo de fondo para buscar archivos

Debe tener mucho cuidado con el acceso de otros hilos a cosas específicas de GUI (es común para muchos kits de herramientas GUI). Si desea actualizar algo en la GUI del hilo de procesamiento, marque esta respuesta que creo que es útil para WinForms. Para WPF, vea esto (muestra cómo tocar el componente en el método UpdateProgress () para que funcione desde otros hilos, pero en realidad no me gusta, no está haciendo CheckAccess() antes de hacer BeginInvoke través de Dispathcer, vea y busque CheckAccess en eso)

Estaba buscando .NET libro específico sobre enhebrar y encontró este (descarga gratuita). Consulte http://www.albahari.com/threading/ para obtener más detalles al respecto.

Creo que encontrará lo que necesita para iniciar la ejecución como un nuevo hilo en las primeras 20 páginas y tiene muchas más (no estoy seguro sobre los fragmentos específicos de GUI que quiero decir estrictamente específicos para el subprocesamiento). Estaría encantado de escuchar qué piensa la comunidad sobre este trabajo porque estoy leyendo este. Por ahora parecía bastante limpio para mí (para mostrar los métodos y tipos específicos de .NET para enhebrar). También cubre .NET 2.0 (y no antiguo 1.1) lo que realmente aprecio.

Recomiendo mirar la Biblioteca de Power Threading de Jeff Richter y específicamente el IAsyncEnumerator. Eche un vistazo al video en el blog de Charlie Calvert donde Richter lo revisa para obtener una buena perspectiva general.

No se deje intimidar por el nombre porque hace que las tareas de progtwigción asíncrona sean más fáciles de codificar.