2009-02-14 2 views
2

Je réalise que je ne peux pas accéder aux contrôles de formulaire à partir du gestionnaire d'événements DoWork d'un BackgroundWorker. (Et si j'essaye, j'obtiens une exception, comme prévu).A quoi puis-je accéder à partir d'un BackgroundWorker sans "Cross Threading"?

Cependant, suis-je autorisé à accéder à d'autres objets (personnalisés) qui existent sur mon formulaire? Par exemple, j'ai créé une classe "Settings" et l'ai instanciée dans mon formulaire et il semble que je puisse lire et écrire dans ses propriétés.

Est-ce juste de la chance que cela fonctionne?

Et si j'avais une classe statique? Serais-je en mesure d'y accéder en toute sécurité?

Répondre

4

@Engram:

Vous avez obtenu l'essentiel de celui-ci - CrossThreadCalls sont juste une belle fonctionnalité MS mis dans le .NET Framework pour éviter le type « bonehead » d'erreurs de programmation parallèle. Il peut être remplacé, comme je suppose que vous l'avez déjà découvert, en définissant la propriété "AllowCrossThreadCalls" sur la classe (et non sur une instance de la classe, par exemple set Label.AllowCrossThreadCalls et non lblMyLabel.AllowCrossThreadCalls) .

Mais, plus important encore, vous avez raison d'utiliser un mécanisme de verrouillage. Chaque fois que vous avez plusieurs threads d'exécution (threads, processus ou autres), vous devez vous assurer que lorsque vous avez un thread lire/écrire dans une variable, vous ne voulez probablement pas d'autres threads et changer cette valeur sous les pieds du premier fil. Le .NET FRAMEWORK fournit en réalité plusieurs autres mécanismes qui pourraient être plus utiles, selon les circonstances, que le verrouillage du code. La première consiste à utiliser une classe Monitor, ce qui a pour effet de verrouiller un objet particulier. Lorsque vous utilisez cela, d'autres threads peuvent continuer à s'exécuter, tant qu'ils n'essaient pas de verrouiller le même objet. Une autre idée de programmation parallèle très utile et commune est la Mutex (ou Semaphore). Le Mutex est fondamentalement comme un jeu de Capture du drapeau entre vos discussions. Si un thread attrape le drapeau, aucun autre thread ne peut l'attraper avant que le premier thread ne le lâche. (Un Sémaphore est juste comme un Mutex, sauf qu'il peut y avoir plus d'un drapeau dans un jeu.)

Évidemment, aucun de ces concepts ne fonctionnera dans chaque problème particulier - mais avec quelques outils supplémentaires pour vous aider pourrait être utile un jour :)

+0

Merci de votre contribution Mike. Très utile. – James

1

Vous devez communiquer avec l'interface utilisateur via les événements ProgressChanged et RunWorkerCompleted (et jamais la méthode DoWork() comme indiqué).

En principe, vous pouvez appeler IsInvokeRequired, mais les concepteurs de la classe BackgroundWorker ont créé l'événement de rappel ProgressChanged dans le but de mettre à jour les éléments de l'interface utilisateur.

[Remarque: Les événements BackgroundWorker ne sont pas rassemblés sur les limites AppDomain. N'utilisez pas un composant BackgroundWorker pour effectuer des opérations multithread dans plusieurs AppDomain.]

MSDN Ref.

+0

Merci. Donc dites-vous que je ne dois jamais accéder à mon objet Settings dans mon formulaire à partir de BackgroundWorker? La seule raison pour laquelle je pose cette question est parce que cela a fonctionné. Je pensais que .NET était toujours destiné à vous donner une CrossThreadingException? – James

+0

Il donnera l'exception de threading croisé s'il arrive que ce n'est pas l'excution de gestion de thread UI à ce point. Donc, sans marshalling explicite sur le thread UI (via IsInvokerequired et Invoke suivant si nécessaire) il est dangereux d'accéder aux éléments de l'interface utilisateur. –

+0

Oh, je vois, donc dans mon scénario soit le thread UI ou le thread BGW peut être appelé à mettre à jour le contenu de mon objet Paramètres? – James

-1

Vous ne pouvez pas accéder aux contrôles créés dans un thread à partir d'un autre thread. Vous pouvez utiliser la classe Settings que vous avez mentionnée ou utiliser la propriété InvokeRequired et les méthodes de contrôle Invoke.

Je vous suggère de regarder les exemples sur ces pages:

http://msdn.microsoft.com/en-us/library/ms171728.aspx

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx

+0

> Vous ne pouvez pas accéder aux contrôles créés dans un thread à partir d'un autre thread. Oui, vous pouvez. Vous devrez juste l'appeler, c'est-à-dire if (listbox1.InvokeRequired) listbox1.Invoke (new MethodInvoker (delegate {...})); else ... –

+0

N'est-ce pas ce que j'ai écrit? –

1

Ok, je l'ai fait quelques recherches sur ce sujet et je pense avoir une réponse. (Laissez les votes décider si j'ai raison!)

La réponse est .. vous pouvez accéder à n'importe quel objet personnalisé qui est dans la portée, mais votre accès ne sera pas thread-safe.

Pour garantir la sécurité des threads, vous devez probablement utiliser lock. Le mot clé lock empêche plusieurs threads d'exécuter un code particulier. (Sous réserve de l'utiliser correctement!)

L'exception Cross Threading qui se produit lorsque vous essayez d'accéder à un contrôle est un mécanisme de sécurité spécialement conçu pour les contrôles. (Il est plus facile et probablement plus efficace de faire en sorte que l'utilisateur fasse des appels sécurisés pour les threads, alors il faut concevoir les contrôles eux-mêmes pour qu'ils soient sécurisés pour les threads).

Questions connexes