Pourquoi une variable locale est-elle accessible dans un autre thread créé dans la même classe?
Je ne pouvais pas vraiment trouver quelque chose sur ce sujet, donc merci de me diriger vers la bonne direction, si une question existe déjà.
De ce que j'ai appris .NET, il n'est pas possible d'accéder à des variables à travers les différents threads (corrigez-moi si cet énoncé est faux, c'est juste ce que j'ai lu quelque part).
Maintenant dans ce codesample, cependant, il semble donc qu'il ne devrait pas travailler:
class MyClass
{
public int variable;
internal MyClass()
{
Thread thread = new Thread(new ThreadStart(DoSomething));
thread.IsBackground = true;
thread.Start();
}
public void DoSomething()
{
variable = 0;
for (int i = 0; i < 10; i++)
variable++;
MessageBox.Show(variable.ToString());
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void SomeMethod();
{
MyClass mc = new MyClass();
}
}
Quand je lance SomeMethod()
ne le sont pas .NET lever une exception, parce que l'objet créé mc
s'exécute dans un thread différent de celui créé au sein de la mc
-initialiseur et ce nouveau thread est en train d'essayer d'accéder à la variable locale de mc
?
La MessageBox
montre 10
(non) prévu mais je ne suis pas sûr de savoir pourquoi cela devrait fonctionner.
Peut-être que je ne savais pas quoi chercher, mais pas de filetage-sujet que j'ai pu trouver, permettrait de répondre à cette question, mais peut-être que mon idée de variables et de threads est mauvais.
source d'informationauteur phil13131
Vous devez vous connecter pour publier un commentaire.
Cette affirmation est complètement fausse, donc considérez cela comme votre correction.
Vous avez probablement lu quelque part que variables locales ne peut pas être accédé à travers les différents threads. Cette déclaration est aussi faux, mais il est généralement indiqué. L'énoncé correct est que les variables locales qui ne sont pas
yield return
ouyield break
)ne peut pas être accédé par plusieurs threads. Et de même que la revendication est un peu douteuses; il y a des manières de le faire avec des pointeurs et
unsafe
de blocs de code, mais c'est une très mauvaise idée de tenter de le faire.Je note aussi que votre question porte sur les variables locales, mais donne ensuite un exemple de champ. Un champ est, par définition, pas une variable locale. Une variable locale est, par définition, local à un corps de méthode. (Ou corps du constructeur, de l'indexeur corps, etc.) Assurez-vous que vous êtes clair sur ce point. La définition des caractéristiques d'un local n'est pas qu'il est "sur la pile" ou quelque chose de ce genre; le "local" d'une partie d'un local, c'est que son nom n'est pas significatif à l'extérieur du corps de la méthode.
Dans le cas général: une variable est un emplacement de stockage qui fait référence à mémoire. Un thread est une point de contrôle dans un processus deet tous les threads d'un processus partagent le même espace mémoire; c'est ce qui les rend fils et pas processus. Donc, en général, toutes les variables peuvent être accessibles par plusieurs threads en tout temps et dans tous les ordres, moins qu'un mécanisme est mis en place pour empêcher que.
Permettez-moi de dire que de nouveau, juste pour s'assurer qu'il est absolument cristal clair dans votre esprit: la bonne façon de penser au sujet d'un programme monothread, c'est que toutes les variables sont stable à moins que quelque chose leur fait modifier. La bonne façon de penser au sujet d'un programme multi-threadé, c'est que toutes les variables sont la mutation constante dans aucun ordre particulier à moins que quelque chose est en les gardant toujours ou bien ordonné. C'est la raison fondamentale de la mémoire partagée modèle de multithreading est si difficileet pourquoi vous devriez éviter.
Dans votre exemple, les deux fils ont accès à
this
et, par conséquent, les deux threads peuvent voir la variablethis.variable
. Vous avez mis en place aucun mécanisme pour l'en empêcher, et, par conséquent, les deux threads peuvent être l'écriture et la lecture de cette variable dans n'importe quel ordre, l'objet de très peu de contraintes, en effet. Certains de ces mécanismes, vous pourriez avoir mis en œuvre pour apprivoiser ce problème sont:ThreadStatic
. Cela entraîne une nouvelle variable à créer sur chaque thread.volatile
. Ce faisant impose certaines restrictions sur la façon dont les lectures et les écritures peuvent être observés à être commandés, et impose certaines restrictions sur les optimisations apportées par le compilateur ou le PROCESSEUR qui pourrait provoquer des résultats inattendus.lock
déclaration autour de chaque utilisation de la variable.Sauf si vous avez un profonde compréhension de multi-threading et processeur optimisations, je recommande contre toute option sauf le dernier.
Maintenant, supposons que vous ne voulez vous assurer que l'accès à la variable a échoué sur un autre thread. Vous pourriez avoir le constructeur de la capture de l'ID de thread le thread de création et le ranger. Ensuite, vous pouvez accéder à la variable par l'intermédiaire d'une propriété de lecture/définition, où les getter et setter vérifier le courant ID de thread, et lève une exception si ce n'est pas le même que l'ID de thread.
Essentiellement ce que cela fait, c'est les rouleaux de votre propre single threaded apartment modèle de thread. Un "single threaded apartment" l'objet est un objet qui ne peut être accessible légalement sur le thread qui l'a créé. (Vous achetez un TÉLÉVISEUR, vous le mettez dans votre appartement, seules les personnes de votre appartement sont autorisés à regarder la TV.) Les détails de mono-thread appartements vs multithread appartements vs gratuit filetage être assez compliqué; voir à cette question pour plus d'arrière-plan.
Pourriez-vous expliquer le personnel et les MTA?
C'est pourquoi, par exemple, vous ne devez jamais accéder à un élément d'INTERFACE utilisateur que vous créez sur le thread d'INTERFACE utilisateur à partir d'un thread de travail; les éléments de l'INTERFACE utilisateur sont les objets STA.
Qui n'est pas correct. Une variable peut être consulté à partir de n'importe où qu'il soit dans la portée.
Vous devez faire preuve de prudence lors de l'accès à la même variable à partir de plusieurs threads car chaque thread peut agir sur la variable à un non-déterministe en temps conduisant à subtile, difficile à résoudre des bugs.
Il est un remarquable site web qui couvre le filetage .NET à partir de la base des concepts avancés.
http://www.albahari.com/threading/
Je suis un peu en retard et la réponse @Eric J. a donné est merveilleux et le point.
Je veux juste ajouter un peu de clarté à un autre problème dans votre perception de fils et de variables.
Vous l'avez dit dans votre question du titre de "variable d'être accessible dans un autre thread".
Ajoutant à cela est le fait que, dans votre code, vous avez accès à votre variable à partir d'exactement 1 fil de qui est le fil qui vient d'être créé ici:
Toutes ces choses m'a fait réaliser qu'on avait peur qu'un thread différent de celui qui crée l'instance de
MyClass
va utiliser quelque chose de l'intérieur de cette instance.Les faits suivants sont importants pour une vue plus claire de ce que le multithreading est (c'est plus simple que vous le pensiez):
MODIFIER
Je vois les mots la sécurité des threads est apparu sur ce fil de réponses.
Dans le cas où vous êtes peut-être vous demandez-vous ce que ces mots signifient je vous recommande cet excellent article de @Eric Lippert:
http://blogs.msdn.com/b/ericlippert/archive/2009/10/19/what-is-this-thing-you-call-thread-safe.aspx
Pas, vous l'avez à l'arrière, l'accessibilité des données tant qu'elle est toujours dans la portée.
Vous devez vous prémunir contre le problème inverse, deux threads accèdent aux mêmes données au même moment, ce qui est appelé une condition de course. Vous pouvez utiliser une technique de synchronisation comme
lock
pour empêcher que cela arrive, mais si utilisé correctement, il peut conduire à l'impasse.Lire C# Threading .NET pour un tutoriel.
Emplacements de mémoire ne sont pas liés à un seul thread. Il serait vraiment gênant si elles l'étaient. De mémoire dans le CLR est isolé à l' domaine d'application limite. C'est pourquoi il est une instance séparée de chaque variable statique par Domaine d'application. Cependant, les threads ne sont pas liés à un domaine d'application particulier. Ils peuvent exécuter du code dans plus d'un domaine d'application ou aucun (code non managé). Ce qu'ils ne peuvent pas faire est d'exécuter du code à partir de plus d'un domaine d'application en même temps. Ce que cela signifie, c'est qu'un thread ne peut pas avoir simultanément accès à des structures de données à partir de deux différents domaines d'application. C'est pourquoi vous devez utiliser marshaling techniques (via
MarshalByRefObject
par exemple) ou de l'utilisation des protocoles de communication comme .NET Remoting ou WCF pour accéder à des structures de données à partir d'un autre domaine d'application.Envisager l'unicode suivants de l'art diagramme d'un processus d'hébergement de la CLR.
Vous pouvez voir que chaque processus peut avoir plus d'un domaine d'application et qu'un thread peut exécuter du code à partir de plus d'un d'entre eux. J'ai aussi essayé d'illustrer le fait qu'un thread peut exécuter du code non managé ainsi, en montrant son existence à l'extérieur de la gauche et la droite AppDomain blocs.
Donc, fondamentalement, un thread a trivial et non-trivial accès à toutes les structures de données dans le même domaine d'application qu'il est actuellement en cours d'exécution. J'utilise le terme "négligeable" pour inclure l'accès à la mémoire (structures de données, variables, etc.) via publics, protégés ou les membres d'une classe à l'autre. Un thread en aucune manière, n'empêche que cela se produise. Cependant, l'utilisation de la réflexion que vous pouvez toujours gagner de l'accès à même les membres privés d'une autre classe. C'est ce que j'appelle la non-trivial d'accès. Oui, elle implique un peu plus de travail de votre part, mais il n'y a rien sinon envie d'aller sur une fois que vous avez terminé la réflexion des appels (qui, par la façon dont doivent être autorisés par le code de la sécurité d'accès, mais c'est un autre sujet). Le point est qu'un thread a accès à peu près tous de la mémoire dans le même domaine d'application, il est en cours d'exécution.
La raison pour laquelle un thread a accès à presque tout dans le même domaine d'application est parce qu'il serait incroyablement restrictive si elle n'a pas. Les développeurs ont à mettre en avant beaucoup d'effort supplémentaire à l'action des structures de données entre les classes lorsque l'on travaille dans un environnement multithread.
Donc, pour résumer les points saillants:
1Même le La singularité du système d'exploitation semble directement la carte .NET threads pour le système d'exploitation et le matériel.