with visual threadstart threads thread new multi method example español book c# multithreading

visual - threadstart c#



En C#, ¿cuál es la forma recomendada de pasar datos entre 2 hilos? (9)

En efecto, ha creado una versión para pobres de un ThreadPool. Su segundo hilo simplemente está sentado sin hacer nada y sin una buena cantidad de trabajo de su parte, no puede lograr que haga el trabajo por usted. Tendría que pasar a los delegados a una cola para que su hilo se arranque y se ejecute.

Su mejor opción es hacer lo que usted pretende y simplemente usar .NET ThreadPool y darle trabajo para hacerlo.

Tengo mi hilo principal de GUI y un segundo hilo ejecutándose dentro de su propio ApplicationContext (para mantenerlo vivo, incluso cuando no hay trabajo por hacer). Quiero llamar a un método en mi segundo hilo desde mi hilo GUI, pero si solo llamo a thread.Method (); parece estar ejecutándose en mi hilo principal de GUI y hace que mi GUI no responda. ¿Cuál es la mejor manera de llamar a métodos en diferentes hilos?

Actualización: Lo que realmente quiero hacer aquí es comunicarme entre 2 hilos, no comunicarme con una GUI. La interfaz gráfica de usuario simplemente pasa a ser uno de los hilos que necesitarán comunicarse con mi segundo hilo.

Actualización # 2: Ok, realmente me falta algo. Creé un evento y un delegado e hice que mi hilo de trabajo se suscribiera al evento. Pero cuando llamo a Invoke (MyEvent); desde mi interfaz gráfica de usuario, el trabajo que realiza el subproceso de trabajo termina en el hilo de la GUI y cuelga el subproceso de GUI hasta que finaliza el proceso. ¿Es lo que estoy tratando de hacer incluso posible, sin interrogar sobre un objeto estático?


La conveniencia de Control.BeginInvoke () es difícil de dejar pasar. No es necesario. Agregue una nueva clase a su proyecto y pegue este código:

using System; using System.Threading; using System.Windows.Forms; public partial class frmWorker : Form { public frmWorker() { // Start the worker thread Thread t = new Thread(new ParameterizedThreadStart(WorkerThread)); t.IsBackground = true; t.Start(this); } public void Stop() { // Synchronous thread stop this.Invoke(new MethodInvoker(stopWorker), null); } private void stopWorker() { this.Close(); } private static void WorkerThread(object frm) { // Start the message loop frmWorker f = frm as frmWorker; f.CreateHandle(); Application.Run(f); } protected override void SetVisibleCore(bool value) { // Shouldn''t become visible value = false; base.SetVisibleCore(value); } }

Aquí hay un código de muestra para probarlo:

public partial class Form1 : Form { private frmWorker mWorker; public Form1() { InitializeComponent(); mWorker = new frmWorker(); } private void button1_Click(object sender, EventArgs e) { Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); mWorker.BeginInvoke(new MethodInvoker(RunThisOnThread)); } private void RunThisOnThread() { Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId); } private void button2_Click(object sender, EventArgs e) { mWorker.Stop(); } }


Ponga un ciclo en su segundo hilo, que duerma la mayor parte del tiempo, pero cada [Intervalo] se activa y comprueba una variable compartida que le dice si ejecutar su método o no, y si ese booleano compartido se establece en verdadero, entonces ejecuta un método que realiza cualquier tarea que intente realizar ... En ese método, haga que el método reúna los datos requeridos de otra variable compartida.

En el hilo de la GUI principal, coloque los datos en la variable compartida del parámetro del método, luego configure la variable compartida booleana "Ejecutar" como verdadera ...

Dentro del método de trabajador, recuerde restablecer la variable de "ejecución" bool compartida a falso cuando haya terminado, por lo que el bucle ganó; t ejecutar la misma instancia una y otra vez ...


Supongo que algún evento en la GUI requiere que comience una tarea de larga ejecución que se ejecute en segundo plano; hay dos formas principales de hacerlo. Si simplemente desea llamar a un método en un hilo diferente, puede hacerlo llamando a los métodos sincrónicos de manera asincrónica . Normalmente hago algo como esto:

//delegate with same prototype as the method to call asynchrously delegate void ProcessItemDelegate(object item); //method to call asynchronously private void ProcessItem(object item) { ... } //method in the GUI thread private void DoWork(object itemToProcess) { //create delegate to call asynchronously... ProcessItemDelegate d = new ProcessItemDelegate(this.ProcessItem); IAsyncResult result = d.BeginInvoke(itemToProcess, new AsyncCallback(this.CallBackMethod), d); } //method called when the async operation has completed private void CallbackMethod(IAsyncResult ar) { ProcessItemDelegate d = (ProcessItemDelegate)ar.AsyncState; //EndInvoke must be called on any delegate called asynchronously! d.EndInvoke(ar); }

Tenga en cuenta al usar este método que la devolución de llamada se ejecuta en el hilo de fondo, por lo que cualquier actualización de la GUI se debe hacer mediante Invoke.

Alternativamente, podría usar el estado compartido para comunicarse entre hilos y usar un EventWaitHandle para señalar las actualizaciones al estado compartido; en este ejemplo, un método en la GUI agrega elementos de trabajo a una cola que se manejarán en segundo plano. El hilo de trabajo procesa los elementos de la cola cuando el trabajo está disponible.

//shared state private Queue workQueue; private EventWaitHandle eventHandle; //method running in gui thread private void DoWork(Item itemToProcess) { //use a private lock object instead of lock... lock(this.workQueue) { this.workQueue.Add(itemToProcess); this.eventHandle.Set(); } } //method that runs on the background thread private void QueueMonitor() { while(keepRunning) { //if the event handle is not signalled the processing thread will sleep here until it is signalled or the timeout expires if(this.eventHandle.WaitOne(optionalTimeout)) { lock(this.workQueue) { while(this.workQueue.Count > 0) { Item itemToProcess = this.workQueue.Dequeue(); //do something with item... } } //reset wait handle - note that AutoResetEvent resets automatically this.eventHandle.Reset(); } } }


Use un objeto de sincronización para señalar el hilo que necesita para procesar los datos nuevos (o el nuevo estado de la GUI). Una forma relativamente simple de hacer esto es usar un objeto de evento. Aquí hay un desglose de cómo funcionaría eso:

  1. La GUI enhebra un segundo hilo y comparte un objeto de evento (para que ambos lo sepan)
  2. El segundo hilo normalmente se ejecuta en un bucle de algún tipo, y cada vez que espera que el evento sea señalado
  3. La secuencia de comandos GUI señala el evento cuando necesita el segundo hilo para hacer algo
  4. Cuando se realiza el segundo hilo, restablece el evento y espera nuevamente (o sale)


Puedes usar eventos o, como dijo Grauenwolf, un aviso de mensaje. Envuelvo cada uno de mis hilos como singleton de gestión, desde allí puedes implementarlos fácilmente. Incluso podría hacer las propiedades públicas de los pobres para dar vuelta las cosas.

También podría implementar una máquina de estados, y en lugar de pasar mensajes, cada subproceso podría controlarse mutuamente


Amigo, lee el ebook de .NET de franqueo libre de Albahari. Estoy conectado a él de alguna manera, así que esto no es un enchufe. Lo leí, mis compañeros de trabajo lo leyeron y lo he usado muchas veces.

Recomendaría crear una clase de productor / consumidor, donde puede iniciar un único hilo que espere (sin bloqueo), poner tareas en cola y señalizarlo para que comience a funcionar.

solo google para eso.


Wow, no puedo creer cómo la gente no se molestó en leer la pregunta.

De todos modos, esto es lo que hago.

  1. Crea tus clases de "mensaje". Esto almacena toda la información que desea compartir.
  2. Cree una cola <T> para cada hilo. Use un SyncLock (bloqueo de C #) para leer / escribir en él.
  3. Cuando desee hablar con un hilo, envíele un objeto de mensaje con una copia de toda la información que necesita agregando el mensaje a la cola.
  4. El hilo de trabajo puede leer desde la cola, leer y procesar cada mensaje en orden. Cuando no hay mensajes, simplemente duerme.

Asegúrese de no compartir objetos entre los dos hilos. Una vez que el hilo de su GUI pega un mensaje en la cola, el hilo de la GUI ya no posee el mensaje. No puede contener una referencia al mensaje o te meterás en problemas.

Esto no le proporcionará el mejor rendimiento posible, pero será lo suficientemente bueno para la mayoría de las aplicaciones. Y más importante aún, hará que sea mucho más difícil cometer un error.

ACTUALIZACIÓN: No use un SyncLock y una cola. En su lugar, use un ConcurrentQueue, que manejará cualquier bloqueo automáticamente para usted. Obtendrás un mejor rendimiento y es menos probable que cometas un error.