2010-03-17 9 views
41

He intentado implementar un patrón productor/consumidor en C#. Tengo un hilo de consumidor que supervisa una cola compartida y un hilo productor que coloca elementos en la cola compartida. El subproceso productor está suscrito para recibir datos ... es decir, tiene un controlador de eventos, y simplemente se sienta y espera a que se active un evento OnData (los datos se envían desde una API de terceros). Cuando obtiene los datos, los pega en la cola para que el consumidor pueda manejarlos.En .NET, ¿en qué secuencia se manejarán los eventos?

Cuando el evento OnData se dispara en el productor, esperaba que fuera manejado por mi hilo productor. Pero eso no parece ser lo que está sucediendo. ¡El evento OnData parece como si estuviera siendo manejado en un nuevo hilo en su lugar! ¿Es así como .net siempre funciona ... los eventos se manejan en su propio hilo? ¿Puedo controlar qué hilo manejará los eventos cuando se generan? ¿Qué ocurre si cientos de eventos se generan casi simultáneamente ... tendrían cada uno su propio hilo?

+0

Podría ser útil publicar algún código, y/o las clases que está utilizando. –

+0

¿Estás hablando de eventos en el sentido de palabra clave 'evento' de C#, o eventos en el sentido 'EventWaitHandle'? Creo que deberías publicar un código ... –

+0

@codeka: suena como 'evento', dada su publicación. –

Respuesta

22

A menos que haga la clasificación, un evento se ejecutará en cualquier hilo que lo invoque; no hay nada de especial en la forma en que se invocan los eventos, y el hilo del productor no tiene un controlador de eventos, el hilo del productor simplemente dijo "hey, cuando dispare este evento, llame a esta función". No hay nada allí que provoque la ejecución del evento en el hilo adjunto, ni en su propio hilo (a menos que usara BeginInvoke en lugar de invocar el delegado del evento normalmente, pero esto solo lo ejecutará en el ThreadPool).

74

Después de volver a leer la pregunta, creo que entiendo el problema ahora. Es, básicamente, tiene algo como esto:

class Producer 
{ 
    public Producer(ExternalSource src) 
    { 
     src.OnData += externalSource_OnData; 
    } 

    private void externalSource_OnData(object sender, ExternalSourceDataEventArgs e) 
    { 
     // put e.Data onto the queue 
    } 
} 

Y entonces usted tiene un hilo consumidor que tira cosas de esa cola. El problema es que el evento OnData es disparado por su objeto ExternalSource, en cualquier hilo en el que se esté ejecutando.

C# event s son básicamente una colección de delegados fácil de usar y "disparar" un evento simplemente hace que el tiempo de ejecución recorra todos los delegados y los active uno a la vez.

Por lo tanto, se llama al controlador de eventos OnData en el hilo en el que se está ejecutando el ExternalSource.

+1

Gracias Codeka, lo tienes exactamente. Comprobaré en qué hilo se están produciendo los eventos externalSource. Aprecio la ayuda. – Ben

+13

@Ben - Debe marcar esto como la respuesta aceptada. Esto ayudaría a otros a ver la respuesta más fácilmente. –

+1

las cosas son diferentes cuando se desencadenan eventos con Invoke y BeginInvoke ..BeginInvoke invoca al suscriptor de evento en un hilo diferente de threadpool (en un hilo de fondo) –

7

La generación de un evento con Invoke es lo mismo que llamar a un método: se ejecuta en el mismo hilo que lo planteó.

La creación de un evento con BeginInvoke utiliza ThreadPool. Aquí hay algunos minor details

-3

tienes que usar manejadores de eventos automáticos para este problema ..... en prevenir automáticamente cuando los productores activan la señal luego el consumidor restablece su señal y consume ... después de consumir consuma la señal establecida, solo el productor producido. ..

AutoResetEvent pro = new AutoResetEvent(false); 
AutoResetEvent con = new AutoResetEvent(true); 

public void produser() 
{ 

    while(true) 
    { 
     con.WaitOne(); 

     pro.Set(); 
    } 
} 

public void consumer() 
{ 
    while (true) 
    { 
    pro.WaitOne(); 
     .................**** 

    con.Set(); 
    } 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    Thread th1 = new Thread(produser); 
    th1.Start(); 
    Thread th2 = new Thread(consumer); 
    th2.Start(); 
} 
Cuestiones relacionadas