2010-06-28 10 views
2

J'ai donc eu un nouveau problème ...Vérificateur de proxy multithread C#

J'écris un proxychecker multithread dans C#. J'utilise BackgroundWorkers pour résoudre le problème du multithreading.

Mais j'ai des problèmes de coordination et d'affectation des proxys laissés en file d'attente aux travailleurs en cours d'exécution. Cela fonctionne la plupart du temps mais parfois aucun résultat ne revient, donc certains proxys sont «perdus» pendant le processus.

Cette liste représente la file d'attente et est remplie avec les identifiants des proxys dans un ListView.

private List<int> queue = new List<int>(); 

private int GetNextinQueue() 
    { 
     if(queue.Count > 0) 
     { 
      lock (lockqueue) 
      { 
       int temp = queue[0]; 
       queue.Remove(temp); 
       return temp; 
      } 
     } 
     else 
      return -1; 
    } 

est dessus de ma méthode pour obtenir la prochaine proxy dans la file d'attente, j'utilise l'instruction de verrouillage pour éviter que les conditions de course, mais je ne suis pas sûr si son assez ou si elle ralentit le processus, car il rend les autres threads attendez ... (lockqueue est un objet juste utilisé pour le verrouillage)

Donc ma question est, comment est-il possible que certains proxys ne sont pas vérifiés (même si le ping échoue le contrôle devrait retourner quelque chose, mais parfois il ya juste rien) et comment puis-je optimiser ce code pour la performance?

Voici le reste du code que je considère important pour cette question http://pastebin.com/iJduX82b

Si quelque chose manque juste écrire un commentaire

Merci :)

Répondre

1

Si vous êtes intéressé par une élégance simple, utilisez une file d'attente:

private Queue<int> queue = new Queue<int>(); 
    private int GetNextinQueue() 
    { 
     lock (queue) { return queue.Count > 0 ? queue.Dequeue() : -1; } 
    } 
+0

Merci, vraiment belle solution. Et merci à tous pour votre aide, j'apprécie énormément cela mais malheureusement je ne peux accepter qu'une seule réponse. Le problème avec les proxies "perdus" est résolu maintenant je pense. – Chilln

2

Quelques choses:

  1. Tous les accès au champ queue doivent être entrés dans un bloc lock (lockqueue) - ceci inclut le if (queue.Count > 0) ligne ci-dessus. Ce n'est pas une question de performance: votre application ne fonctionnera pas si vous n'acquittez pas la serrure lorsque cela est nécessaire.

  2. De votre pastebin, l'appel à RunWorkerAsync semble suspect. Actuellement, chaque BackgroundWorker partage le même tableau d'arguments; vous devez donner à chacun sa propre copie.

4

La vérification de queue.Count doit être effectuée dans l'instruction lock. Otberwise vous pouvez vérifier que queue.Count> 0, mais au moment où vous êtes en mesure d'entrer le verrou, un autre thread peut avoir supprimé un élément de la file d'attente, et vous allez ensuite appeler Remove sur une file d'attente éventuellement vide.

Vous pouvez modifier à:

private int GetNextinQueue() 
    { 
     lock (lockqueue) 
     { 
      if(queue.Count > 0) 
      { 
       int temp = queue[0]; 
       queue.Remove(temp); 
       return temp; 
      } 
      else 
       return -1; 
     } 
    } 

Fondamentalement, si vous voulez garder l'accès à une structure de données avec un verrou, assurez-vous que vous gardez toutes les lectures et écritures de cette structure pour la sécurité des threads.

2

Essayez ceci:

private int GetNextinQueue() 
{ 
    int ret = -1; 
    lock (queue) 
    { 
     if (queue.Count > 0) 
     { 
      int temp = queue[0]; 
      queue.Remove(temp); 
      ret = temp; 
     } 
    } 
    return ret; 
} 

Je ne vous soucier de la performance à ce sujet - il est vrai que d'autres threads bloquent ici si un thread détient le verrou, mais la suppression d'un int d'une liste ne prend très longtemps.

De plus, vous n'avez pas vraiment besoin d'un objet lockqueue - puisque queue est l'objet dont vous voulez verrouiller l'accès, il suffit de l'utiliser.

+1

« En outre, vous ne vraiment pas besoin d'un objet lockqueue - depuis la file d'attente est l'objet que vous souhaitez verrouiller l'accès, il suffit d'utiliser il." - Ne fais pas ça; verrouille sur une instance 'object' séparée à la place. C'est une défense contre d'autres auteurs de classe qui peuvent utiliser 'lock (this)' en interne. –

+0

@Tim Robinson: 'lock (this)' serait considéré comme une mauvaise pratique de programmation (http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.80).aspx), et je doute que les auteurs de 'List' aurait fait cela. – MusiGenesis

+0

Plus de MSDN: "Strictement parlant, l'objet fourni pour verrouiller est utilisé uniquement pour identifier de manière unique la ressource partagée entre plusieurs threads, donc il peut s'agir d'une instance de classe arbitraire. la synchronisation des threads est nécessaire. " – MusiGenesis