2013-02-28 5 views
1

J'ai le code ci-dessous qui produit une sortie incohérente. Parfois, il produit t1 et t2, et parfois il produit t2 double. Ce que je pense en ce moment, c'est ça. Lorsque la sortie est double t2, la valeur de la variable capturée du premier thread est t2 car elle a démarré après la dernière affectation de variable. Ai-je raison?Fil incohérent

Remarque: J'utilise ce code sur une machine lente.

+3

Oui, vous avez raison – MarcinJuraszek

+0

C'est pourquoi ReSharper se plaint de modifier « fermetures » parfois. Vous le résolvez en faisant toujours une copie de l'argument que vous passez à un lambda si vous modifiez cette variable après avoir démarré le lambda dans un thread séparé. –

+0

J'ai ajouté un code monothread démontrant le problème mentionné par @MatthewWatson comme réponse pour référence. –

Répondre

3

Vous avez raison; voir race conditions sur Wikipedia. Par définition, les threads ne s'exécutent pas de façon synchrone. Vous ne devez donc pas vous attendre à ce que l'ordre de votre code détermine sans ambiguïté le comportement de votre programme.

+0

Merci! 'Condition de course' est le terme que je cherche. :) –

+0

+1 pour le bon terme et la note sur la commande des appels. @FreddieFabregas, s'il vous plaît prêter attention à Matthew Watson commentaire - le problème avec votre code est causé par la fermeture et exposée par condition de course. Vous pouvez facilement avoir un comportement similaire confus si au lieu de threads, vous mettez simplement en cache lambda et l'appelez plus tard sur le même thread. –

+0

@AlexeiLevenkov, oui. Je prendrai note de cela. –

1

Oui, c'est un problème simple multi-threading.

Alors que le 1er thread n'est même pas démarré, vous modifiez la valeur de la variable de texte. Ensuite, le 1er thread commence avec la nouvelle valeur et vous avez un double 't2'

1

« il est parfois produire deux t2 »

La valeur du texte a été modifié pour « t2 » avant le premier

new Thread (() => Console.WriteLine (text)).Start(); 

a exécuté

Si vous voulez la cohérence, le changement à:

string text = "t1"; 
new Thread (() => Console.WriteLine (text)).Start(); 

//Thread.Sleep(1); 

string text2 = "t2"; 
new Thread (() => Console.WriteLine (text2)).Start(); 
+0

+1 pour montrer comment éviter de modifier la valeur en fermeture (en capturant 2 variables différentes). –

-1

Par conséquent le moyen le plus simple est d'utiliser un verrou sur la variable

Cela empêche un fil pour accéder à la variable alors qu'il est utilisé par un autre

+0

-1. Ajouter n'importe quel type d'instruction 'lock' ne résoudra rien dans l'échantillon existant en tant que problème provoqué principalement par la fermeture et exposé par le threading. D'un autre côté, si vous montrez un exemple qui fonctionne correctement avec 'lock', cela pourrait très bien être une réponse. –

1

Oui, vous avez la condition de course que tout le monde parle.

Dans votre cas, il expose le comportement des fermetures que la plupart des gens n'attendent pas au premier abord: la fermeture capture la variable, pas sa valeur. Le problème peut être facilement représentée en simple cas de fil:

string text = "t1"; 
Action a1 = () => Console.WriteLine (text); 
a1(); // prints "t1" 
text = "t2"; 
Action a2 =() => Console.WriteLine (text) ; 

a1(); // prints "t2" 
a2();