2009-02-18 5 views
1

J'ai un service Windows qui exécute une méthode lorsque le délai principal des services est écoulé (OnElapse).Comment puis-je gérer quels éléments sont dans le ThreadPool?

La méthode OnElapse obtient une liste de fichiers .xml à traiter. Chaque fichier xml est inséré dans un ThreadPool.

Je veux m'assurer que je n'insère pas 2 XML avec le même nom dans le ThreadPool.

Comment puis-je gérer quels éléments sont dans le ThreadPool? Je veux essentiellement faire ceci:

if xmlfilename not in threadpool 
    insert in threadpool 

Répondre

4

Ceci est assez astucieux car vous devez surveiller de près le ThreadPool et cela nécessitera une forme de synchronisation. Voici un exemple rapide et sale d'un moyen de le faire.

class XmlManager { 
    private object m_lock = new object(); 
    private HashSet<string> m_inPool = new HashSet<string>(); 

    private void Run(object state) { 
    string name = (string)state; 
    try { 
     FunctionThatActuallyProcessesFiles(name); 
    } finally { 
     lock (m_lock) { m_inPool.Remove(name); } 
    } 
    } 

    public void MaybeRun(string xmlName) { 
    lock (m_lock) { 
     if (!m_pool.Add(xmlName)) { 
     return; 
     } 
    } 
    ThreadPool.QueueUserWorkItem(Run, xmlName); 
    } 
} 

Ceci n'est pas une solution infaillible. Il y a au moins une condition de concurrence dans le code. A savoir qu'un élément pourrait être retiré du pool pendant que vous essayez de le rajouter et qu'il ne sera pas réellement ajouté. Mais si vous êtes seulement concerné par leur traitement une seule fois, cela n'a pas d'importance.

+0

Wow, nos solutions sont remarquablement similaires mais j'aime mettre le remove dans un bloc finally, cela souligne le besoin de supprimer l'item quel que soit le résultat du traitement. –

+0

En outre, je ne pense pas que j'appellerais cela une véritable condition de concurrence ou même une faille dans la solution. –

+0

En fait, un autre fichier XML ne touchera pas le serveur tant qu'il n'aura pas été traité, de sorte que la condition de concurrence ne se produira jamais. Merci beaucoup! – Blankman

0

OnElaspe ne peut pas renommer le fichier xml? donc il a un nom unqiue sur le pool de threads. Vous ne pourriez pas faire un dictionnaire> et vérifier cela avant de faire l'insertion?

+0

En fait, je ne veux pas ajouter à la piscine processus soit seulement fichiers xml uniques à la fois (exigence de l'entreprise) – Blankman

0

Quelque chose comme ça ...

Dictionary<ThreadPool, List<String>> poolXmlFiles = new Dictionary<ThreadPool, List<String>>(); 
if(poolXmlFiles.ContainsKey(ThreadPool) && !poolXmlFiles[ThreadPool].Contains(xmlFileName)) 
{ 
    poolXmlFiles[ThreadPool].Add(xmlFileName); 
    //Add the xmlFile to the ThreadPool 
} 

Désolé s'il y a des erreurs de syntaxe, je code en VB ces jours-ci.

+0

mais une fois le thread terminé, comment vais-je supprimer le nom de fichier du dictionnaire? Est-ce threadsafe? – Blankman

+0

C'est threadsafe si vous avez le dictionnaire défini dans votre service. Vous pouvez utiliser un ThreadPool pour une clé dans votre dictionnaire en configurant une autre collection pour associer vos ThreadPools à un type de valeur, comme un entier. Je suppose que vous savez ce que le nom de fichier est lorsque le thread se termine? –

+0

Oui, je connais le nom quand il est complet, vrai! – Blankman

2

Quelque chose comme ça devrait le faire (utiliser un HashSet au lieu d'un dictionnaire si vous utilisez .Net 3.5 ou supérieur):

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace Something 
{ 
    class ProcessFilesClass 
    { 
     private object m_Lock = new object(); 
     private Dictionary<string, object> m_WorkingItems = 
      new Dictionary<string, object>(); 
     private Timer m_Timer; 

     public ProcessFilesClass() 
     { 
      m_Timer = new Timer(OnElapsed, null, 0, 10000); 
     } 

     public void OnElapsed(object context) 
     { 
      List<string> xmlList = new List<string>(); 
      //Process xml files into xmlList 

      foreach (string xmlFile in xmlList) 
      { 
       lock (m_Lock) 
       { 
        if (!m_WorkingItems.ContainsKey(xmlFile)) 
        { 
         m_WorkingItems.Add(xmlFile, null); 
         ThreadPool.QueueUserWorkItem(DoWork, xmlFile); 
        } 
       } 
      } 
     } 

     public void DoWork(object xmlFile) 
     { 
      //process xmlFile 
      lock (m_Lock) 
      { 
       m_WorkingItems.Remove(xmlFile.ToString()); 
      } 
     } 
    } 
} 
+0

:-) –