J'ai essayé d'implémenter un modèle producteur/consommateur en c #. J'ai un thread consommateur qui surveille une file d'attente partagée et un thread producteur qui place des éléments dans la file d'attente partagée. Le thread producteur est abonné pour recevoir des données ... c'est-à-dire qu'il a un gestionnaire d'événements, il reste assis et attend qu'un événement OnData se déclenche (les données sont envoyées à partir d'une API tierce). Lorsqu'il obtient les données, il les place dans la file d'attente afin que le consommateur puisse les gérer.
Lorsque l'événement OnData se déclenche dans le producteur, je m'attendais à ce qu'il soit géré par mon thread producteur. Mais cela ne semble pas être le cas. L'événement OnData semble plutôt être géré sur un nouveau thread! Est-ce ainsi que .net fonctionne toujours ... les événements sont gérés sur leur propre thread? Puis-je contrôler quel thread gérera les événements lorsqu'ils sont déclenchés? Et si des centaines d'événements sont déclenchés presque simultanément ... chacun aurait son propre fil?
Après avoir relu la question, je pense que je comprends maintenant le problème. Vous avez essentiellement quelque chose comme ça:
class Producer
{
public Producer(ExternalSource src)
{
src.OnData += externalSource_OnData;
}
private void externalSource_OnData(object sender, ExternalSourceDataEventArgs e)
{
// put e.Data onto the queue
}
}
Et puis vous avez un fil de consommation qui retire des trucs de cette file d'attente. Le problème est que l'événement OnData est déclenché par votre objet ExternalSource
- sur le thread sur lequel il se trouve.
C # event
s ne sont en fait qu'une collection de délégués facile à utiliser et le "déclenchement" d'un événement fait simplement que le runtime boucle tous les délégués et les déclenche un à la fois.
Ainsi, votre gestionnaire d'événements OnData est appelé sur le thread sur lequel s'exécute ExternalSource
.
Sauf si vous faites le marshaling vous-même, un événement s'exécutera sur le thread qui l'invoque; il n'y a rien de spécial dans la façon dont les événements sont invoqués, et votre thread producteur n'a pas de gestionnaire d'événements, votre thread producteur a simplement dit "hé, lorsque vous déclenchez cet événement, appelez cette fonction". Il n'y a rien là-dedans qui provoque l'exécution de l'événement sur le thread d'attachement, ni sur son propre thread (à moins que vous n'utilisiez BeginInvoke
plutôt que d'appeler le délégué de l'événement normalement, mais cela l'exécutera simplement sur le ThreadPool
).
Déclencher un événement avec Invoke
équivaut à appeler une méthode - il est exécuté dans le même thread que vous l'avez déclenché.
Déclencher un événement avec BeginInvoke
utilise ThreadPool
. Voici quelques détails mineurs