2010-06-30 8 views
1

J'exécute quatre threads qui obtiennent et définissent la même propriété. Quand j'utilise le point d'arrêt, il me donne le résultat attendu, mais quand je l'exécute directement, il me donne le dernier résultat mis à jour.Comment verrouiller une propriété setter pour un thread

Voici mon code

int Port { get; set; } 
Thread[] tMain= new Thread[4]; 

public void btnListen_Click(object sender, EventArgs e) 
     { 
      for (int i = 0; i < 4; i++) 
      { 
       tMain[i] = new Thread(Connect); 
       tMain[i].IsBackground = true; 
       tMain[i].Start(8000+i); 
      } 
     } 


public void Connect(object _port) 
     { 
      try 
      { 
       lock ((object)Port) 
       { 
        Port = (int)_port; 
       } 
       IPEndPoint ie = new IPEndPoint(IPAddress.Any, Port); 
       Socket listenSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
       listenSock.Bind(ie); 
       listenSock.Listen(100); 
       Thread tListen = new Thread(() => StartListening(listenSock, Port)); 
       tListen.IsBackground = true; 
       tListen.Start(); 
      } 
      catch (SocketException ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 

public void StartListening(Socket _socket, int port) 
     { 
      Socket tempSock,listenerSocket=(Socket)_socket; 
      MessageBox.Show("Thread Started"+port.ToString()); 
      while (true) 
      { 
       MessageBox.Show("Waiting For Connection"); 
       tempSock = listenerSocket.Accept(); 

       Thread tInner = new Thread(ProcessMessages); 
       tInner.IsBackground = true; 
       tInner.Start(tempSock); 
      } 
     } 

Maintenant, ce que je vois ici est lorsque le code est exécuté i obtient 8003 dans toutes les boîtes de message. C'est peut-être parce que le premier thread 3 ne pouvait pas modifier la propriété entre-temps quand il a été accédé. Comment obtenir une serrure dans ce cas.

+0

Pourquoi avez-vous réellement besoin de la propriété "Port"? Il y a beaucoup de problèmes avec ce code, mais commençons par le besoin de cette propriété. Que faire si vous le supprimez simplement et tout le code qui s'y rapporte? Au lieu de "Port" dans l'appel au constructeur IPEndPoint, passez simplement '(int) _port'. Cela ne résoudra-t-il pas tous vos problèmes? –

+0

@Lasse: J'ai précédemment utilisé (int) _port uniquement et quand il a été exécuté avec succès, je l'ai remplacé par la propriété juste pour faire un certain RND et j'ai trouvé ce problème. C'est pourquoi. Sinon, j'ai eu l'idée d'utiliser la collection aussi. –

Répondre

2

Ce code a certainement besoin d'être refactorisé pour commencer - trop de threads sont étendus, le tout dans un contexte très étroit!

Réponse courte:

Le problème se résume au fait que Connect fonction n'est pas appelée au moment (ou même ordre) que vous attendez que ce soit, mais seulement lorsque la boucle est terminée.

Réponse longue:

Ce scénario est assez typique des problèmes de concurrence lorsque vous essayez d'utiliser des variables/propriétés d'instance scope dans les fonctions. Pour autant que je sache, le problème de ne pas obtenir la valeur désirée pour Port n'a rien à voir avec le verrouillage en soi. (Il peut être résolu de cette façon, mais pas très gracieusement et pas de la façon dont vous pensez probablement.) En fin de compte vous ne pouvez pas contrôler comment les blocs de temps sont alloués aux différents threads au niveau du processeur, donc vous ne savez pas quelles fonctions sont exécutées dans quel ordre. Vous semblez également mélanger les principes du design (fonctionnel) sans état et apatride, ce qui risque de vous causer des ennuis. Stick à un - de préférence ce dernier dans ce cas - et vous aurez beaucoup plus de succès. Donc j'espère que je suis dur d'être gentil ici en disant qu'il serait probablement utile de lire un peu sur le multithreading - c'est un sujet extrêmement complexe - et de pratiquer certains des principes communs. Bonne chance!

+0

@Noldorin: Il n'y a rien de mieux que de me sentir dur. c'est un plaisir pour moi de savoir cela. Bien que ce fut mon premier programme sur la création de Socket et Multithreading. Et comme on vous l'a dit tout à l'heure que les threads sont appelés après la fin de la boucle, c'était une nouvelle fonctionnalité cachée de thread pour moi. Bien que j'ai 2-3 solutions ici pour utiliser. Soit en utilisant des collections ou en utilisant la valeur statique du port. Quelles autres choses peuvent être faites et si je pense à prendre une serrure alors comment pourrais-je le prendre. Sera-t-il possible ici dans ce scénario d'obtenir un verrou. Comme je pense que le verrouillage n'est pas possible –

+0

Comme expliqué par vous que chaque thread commencera après la fin de la boucle. –

+0

La solution la plus évidente est probablement juste pour se débarrasser de votre variable de classe 'Port' - n'en voyez pas vraiment le besoin de toute façon. Faites tout fonctionnellement, et passez les choses comme paramètres. – Noldorin