J'utilise un objet SynchronizationContext pour ramener les événements au thread d'interface utilisateur de ma DLL qui exécute de nombreuses tâches d'arrière-plan multithread. Je sais que le modèle singleton n'est pas un favori, mais je l'utilise pour maintenant stocker une référence de SynchronizationContext de l'interface utilisateur lorsque vous créez l'objet parent de foo.Utilisation de SynchronizationContext pour renvoyer des événements à l'interface utilisateur pour WinForms ou WPF
public class Foo
{
public event EventHandler FooDoDoneEvent;
public void DoFoo()
{
//stuff
OnFooDoDone();
}
private void OnFooDoDone()
{
if (FooDoDoneEvent != null)
{
if (TheUISync.Instance.UISync != SynchronizationContext.Current)
{
TheUISync.Instance.UISync.Post(delegate { OnFooDoDone(); }, null);
}
else
{
FooDoDoneEvent(this, new EventArgs());
}
}
}
}
Cela ne fonctionne pas du tout dans WPF, la synchronisation de l'interface utilisateur des instances TheUISync (qui soutire de la fenêtre principale) ne correspond jamais à la SynchronizationContext.Current actuelle. Sous forme de fenêtres, quand je fais la même chose, ils vont correspondre après une invocation et nous reviendrons au bon thread.
Mon correctif, que je déteste, ressemble
public class Foo
{
public event EventHandler FooDoDoneEvent;
public void DoFoo()
{
//stuff
OnFooDoDone(false);
}
private void OnFooDoDone(bool invoked)
{
if (FooDoDoneEvent != null)
{
if ((TheUISync.Instance.UISync != SynchronizationContext.Current) && (!invoked))
{
TheUISync.Instance.UISync.Post(delegate { OnFooDoDone(true); }, null);
}
else
{
FooDoDoneEvent(this, new EventArgs());
}
}
}
}
J'espère donc que cet échantillon fait assez de sens pour suivre.
Peu importe quand vous vérifiez, sauf si vous verrouillez quelque chose, je pense que vous pourriez toujours avoir ce problème. Et c'est un problème de threading qui ne peut pas être résolu dans votre classe, il doit être géré dans la classe qui est en train de se connecter à votre événement (ou de vous désabonner de votre événement). abonné pourrait utiliser et je pourrais utiliser pour s'assurer que les événements sont synchronisés. –
Oui et non. "événement public ..." a des problèmes de threading si vous pensez qu'il peut être appelé thread-free. Si deux threads s'abonnent tous deux au même événement en même temps, ils peuvent tous deux ne pas entrer dans la liste d'invocation. Donc, l'hypothèse est toujours que vous avez un certain protocole de threading à l'esprit pour définir l'événement en premier lieu. Le plus commun de ces protocoles est de définir de tels événements uniquement sur le thread d'interface utilisateur, auquel cas le correctif de bogue que j'ai donné fonctionne de manière fiable alors que le code d'origine ne le fait pas. D'un autre côté, si un protocole différent est prévu, vous pouvez avoir besoin d'un verrouillage explicite. –
Pour m'assurer que 'FooDoDoneEvent' n'est pas nul, je crois que ce que vous voulez vraiment faire est d'assigner' FooDoDoneEvent' à une variable locale, vérifiez qu'elle n'est pas nulle, puis appelez 'FooDoDoneEvent (this, new EventArgs()) '. – Charles