2012-01-06 38 views
11

Me pregunto cuál es la mejor manera de implementar la comunicación entre dos hilos. Tengo un hilo que genera un número aleatorio (remitente de clase) y ahora quiero tener otro hilo (receptor de clase) que reciba el número aleatorio generado. Esta es remitente:Enhebrado, comunicación entre dos hilos C#

public class Sender 
{ 
    public int GenerateNumber(){ 


     //some code 
     return randomNumber; 
    } 
} 

Afcourse en la función principal que va a empezar a esos hilos:

static void Main(string[] args){ 

    Sender _sender=new Sender(); 
    Thread thread1=new Thread(new ThreadStart(_sender.GenerateNumber)); 

} 

Agradezco su ayuda

+0

¿Comienzan ambos hilos al mismo tiempo? ¿Qué está haciendo Receiver mientras espera al remitente? ¿Qué hace el emisor después de generar un número aleatorio? – cadrell0

+0

¿ES esto .NET 4? – Yahia

+0

En la función principal, iniciaré ambos subprocesos y el remitente de subprocesos funcionará y luego dormirá durante 3 segundos. También voy a iniciar la instancia de receptor de hilo que recibirá datos ...basiclly threads 'll work untui user Presione la tecla esc ... reciever ll write en los números de consola que recibió. – Avicena00

Respuesta

2

Usted necesitará algún tipo de recurso (lista, cola, etc.) compartido entre el emisor y el receptor. Y deberá sincronizar el acceso a este recurso; de lo contrario, no podrá pasar datos entre los hilos.

19

Si está utilizando .NET 4, le sugiero que utilice una abstracción de nivel superior: Task<TResult>. Su primer hilo puede programar la tarea (que puede terminar creando un hilo, o programarse en un hilo existente de manejo de tareas) y luego puede verificar el estado, bloquear el resultado, etc., según lo crea conveniente.

Si desea hacer más de una tarea de una sola vez, puede utilizar una cola de productor/consumidor. De nuevo, .NET 4 lo ayuda con BlockingCollection<T>.

+1

I sabía que tenía que leer C# en profundidad, así que comenzaré esta tarde :) – Avicena00

+1

@AintMeBabe: para ser sincero, C# en profundidad apenas toca la nueva tarea 'Tarea ' ... investigación en la Biblioteca de tareas paralelas a través de MSDN las publicaciones de blog pueden tener un beneficio más inmediato que el libro. No es que te desanime a largo plazo, por supuesto :) –

+0

¿Qué pasa si no tenemos control sobre el productor; en mi contexto, el hilo A (bajo mi control) hace algo, y necesita esperar que el hilo B genere un evento; el hilo B es generado por una biblioteca. Escucho el evento. ¿Cómo debería el detector de eventos (que se ejecuta en el hilo B) notificar el hilo A? No puedo pensar en nada más que un ManualResetEvent. ¿Hay un mejor enfoque en .net 4? – Jimmy

0

Si todo lo que hace es generar un número aleatorio en un hilo probablemente crearía un objeto seguro para hilos que haga esto en su lugar.

lock(syncRoot) 
{ 
    myCurrentRandom = Generate(); 
    return myCurrentRandom; 
} 
+0

buen punto, esta es solo una función que estoy probando para que las cosas funcionen, después de que el remitente del hilo tenga algunos métodos más – Avicena00

6

He aquí un posible enfoque utilizando un WaitHandle:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     using (ManualResetEvent waitHandle = new ManualResetEvent(false)) 
     { 
      // have to initialize this variable, otherwise the compiler complains when it is used later 
      int randomNumber = 0; 

      Thread thread1 = new Thread(new ThreadStart(() => 
      { 
       randomNumber = _sender.GenerateNumber(); 

       try 
       { 
        // now that we have the random number, signal the wait handle 
        waitHandle.Set(); 
       } 
       catch (ObjectDisposedException) 
       { 
        // this exception will be thrown if the timeout elapses on the call to waitHandle.WaitOne 
       } 
      })); 

      // begin receiving the random number 
      thread1.Start(); 

      // wait for the random number 
      if (waitHandle.WaitOne(/*optionally pass in a timeout value*/)) 
      { 
       _receiver.TakeRandomNumber(randomNumber); 
      } 
      else 
      { 
       // signal was never received 
       // Note, this code will only execute if a timeout value is specified 
       System.Console.WriteLine("Timeout"); 
      } 
     } 
    } 
} 

public class Sender 
{ 
    public int GenerateNumber() 
    { 
     Thread.Sleep(2000); 

     // http://xkcd.com/221/ 
     int randomNumber = 4; // chosen by fair dice role 

     return randomNumber; 
    } 
} 

public class Receiver 
{ 
    public void TakeRandomNumber(int randomNumber) 
    { 
     // do something 
     System.Console.WriteLine("Received random number: {0}", randomNumber); 
    } 
} 


Sólo quería actualizar mi respuesta para proporcionar lo que creo que es el código equivalente para el ejemplo anterior utilizando la clase Task<TResult> en. NET 4 señalado por Jon Skeet en su respuesta. El crédito va a él por señalarlo. Muchas gracias, Jon. Todavía no tengo una razón para usar esa clase, y me sorprendió gratamente cuando vi lo fácil que era usarla.

Aparte de los beneficios de rendimiento que obtiene bajo el capó de usar esta clase, escribir el código equivalente usando la clase Task<TResult> parece ser mucho más fácil. Por ejemplo, el cuerpo del método principal de arriba puede ser reescrito como se muestra a continuación:

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // wait for up to 5 seconds for the getRandomNumber task to complete 
     if (getRandomNumber.Wait(5000)) 
     { 
      _receiver.TakeRandomNumber(getRandomNumber.Result); 
     } 
     else 
     { 
      // the getRandomNumber task did not complete within the specified timeout 
      System.Console.WriteLine("Timeout"); 
     } 

Si usted no tiene ninguna necesidad de especificar un tiempo de espera para la tarea y está dispuesto a esperar indefinidamente a que termine, entonces usted puede escribir esto usando aún menos código:

 Sender _sender = new Sender(); 
     Receiver _receiver = new Receiver(); 

     Task<int> getRandomNumber = Task.Factory.StartNew<int>(_sender.GenerateNumber); 

     // begin receiving the random number 
     getRandomNumber.Start(); 

     // ... perform other tasks 

     // accessing the Result property implicitly waits for the task to complete 
     _receiver.TakeRandomNumber(getRandomNumber.Result); 
+0

gracias :) :) – Avicena00

+0

thumbs up !!!!!! – Avicena00

+0

@AintMeBabe - si usa .NET 4, entonces le recomiendo que consulte la respuesta de Jon Skeet. Parece que puedes hacer lo mismo con mucho menos código usando la clase 'Task '. –

0

La "mejor" forma de implementar la comunicación entre dos hilos realmente depende de lo que necesita ser comunicado. Tu ejemplo parece ser un problema clásico de productor/consumidor. Yo usaría una cola sincronizada. Consulte la documentación de MSDN para Colecciones sincronizadas. Puede usar el método Queue.Synchronized para obtener un contenedor sincronizado para un objeto Queue. Luego, haga que el hilo productor llame a Enqueue() y el consumidor llame a Dequeue().