2010-07-09 2 views
0

Donc d'abord voici un pseudo code de ce que je veux améliorer.Liste de processus <T> membre lorsqu'il est ajouté dans un thread séparé

 
     public List<ProcessData> Processes; 
     System.Threading.Thread ProcessThread; 
     void ProcessLoop() 
     { 
      while (true) 
      { 
       for (int i = 0; i < Processes.Count; i++) 
       { 
        if (HasPriority(Processes[i])) 
        { 
         Process(Processes[i]); 
        } 
       } 
       System.Threading.Thread.Sleep(1000); 
      } 

     } 
     void AddProcessData(ProcessData pd) 
     { 
      Processes.Add(pd); 
      if (Suspended(ProcessThread)) 
       Resume(ProcessThread); 
     } 
     void Startup() 
     { 
      ProcessThread = new System.Threading.Thread(ProcessLoop); 
      ProcessThread.Start(); 
     } 

Donc ce que je veux faire est de remplacer le « sommeil » avec le code qui suspend le fil ou le faire attendre quelque chose est ajouté à la liste, puis la reprendre. J'ai également besoin d'être thread safe, bien sûr.

+0

Avez-vous vraiment besoin de traiter la liste après avoir ajouté une autre donnée de traitement? Et aussi, dans votre version, vous allez traiter tous les éléments de la liste chaque seconde. Est-ce l'intention? – ULysses

+0

Non, j'ai oublié le code pour supprimer les données une fois qu'elles sont traitées. – user230821

Répondre

1

Ce que vous voulez est un événement.

EDIT: pour rendre le filetage sûr.

public List<ProcessData> Processes; 
    System.Threading.Thread ProcessThread; 
    System.Threading.AutoResetEvent ProcessesChangedEvent = new System.Threading.AutoResetEvent(false); 
    void ProcessLoop() 
    { 
     while (true) 
     { 
      // You might want to copy out the entire list as an array instead 
      // if HasPriority or Process take a long time. 
      lock (Processes) 
      { 
       for (int i = 0; i < Processes.Count; i++) 
       { 
        if (HasPriority(Processes[i])) 
        { 
         Process(Processes[i]); 
        } 
       } 
      } 
      ProcessesChangedEvent.WaitOne(...); // timeout? 
     } 

    } 
    void AddProcessData(ProcessData pd) 
    { 
     lock (Processes) 
      Processes.Add(pd); 
     ProcessesChangedEvent.Set(); // you can also use Monitor.PulseAll/Wait 
    } 
    void Startup() 
    { 
     ProcessThread = new System.Threading.Thread(ProcessLoop); 
     ProcessThread.Start(); 
    } 
+0

Comment est-ce que je pourrais sécuriser le filetage? – user230821

+0

Ce code ne supprime pas les éléments qui sont traités et il ne remarquera pas non plus le nouvel élément ajouté jusqu'à la prochaine itération du worker. Et il va bloquer l'appel AddProcessData pour la durée de la boucle de traitement dans un travailleur – ULysses

+0

L'AutoResetEvent est thread bien sûr, non? @Ulysses: C'est un pseudo-code. Cela n'a pas d'importance tant qu'il fait passer le message, ce qu'il a fait. – user230821

0

Découvrez le framework RX de Microsoft. http://rxwiki.wikidot.com/start là vous pouvez obtenir un événement toutes les x secondes et faire quelque chose ensuite. pas besoin de démarrer les threads du tout.

ou d'utiliser une minuterie et d'effectuer la vérification dans l'événement écoulé.

0

Juste au cas où vous avez vraiment besoin de traiter les données qu'une seule fois, voici un code


     public Queue<ProcessData> Processes; 
     System.Threading.Thread[] ProcessThreads = new System.Threading.Thread[5]; 
     System.Threading.Semaphore semToDo = new System.Threading.Semaphore(0,int.MaxValue); 

     void ProcessLoop() 
     { 
      ProcessData pd; 

      while (true) 
      { 
       semToDo.WaitOne(); 
       lock (Processes) 
       { 
        pd = Processes.Dequeue();      
       } 
       Process(pd); 
      } 
     } 

     private void Process(ProcessData processData) 
     { 
      throw new NotImplementedException(); 
     } 

     void AddProcessData(ProcessData pd) 
     { 
      lock (Processes) 
      { 
       Processes.Enqueue(pd); 
      } 
      semToDo.Release(); 
     } 
     void Startup() 
     { 
      //you can even have multiple worker threads now! 

      for(int i = 0; i < 5; i++) 
       ProcessThreads[i] = new System.Threading.Thread(ProcessLoop); 
      foreach (System.Threading.Thread t in ProcessThreads) 
      { 
       t.Start(); 
      } 
     } 
+0

@downrater: s'il vous plaît vous expliquer – ULysses

1

Ce dont vous avez vraiment besoin est un BlockingQueue. Vous pouvez trouver une implémentation de qualité here. Ou si vous utilisez la version 4 du .NET Framework, vous pouvez utiliser la classe BlockingCollection intégrée. Remarquez combien le code est plus facile lorsque vous utilisez ce type de structure de données.

public class YourClass 
{ 
    private BlockingQueue<ProcessData> m_Queue = new BlockingQueue<ProcessData(); 

    private void ProcessLoop() 
    { 
    while (true) 
    { 
     ProcessData item = m_Queue.Dequeue(); 
     if (HasPriority(item)) 
     { 
     Process(item); 
     } 
    } 
    } 

    public void AddProcessData(ProcessData item) 
    { 
    m_Queue.Enqueue(item); 
    } 

    public void Startup() 
    { 
    var thread = new Thread(() => { ProcessLoop(); }); 
    thread.Start(); 
    } 
} 
+0

BlockingQueue est un bon, je ne savais pas qu'il a été ajouté. Dans l'implémentation que vous avez liée, j'ajouterais un peu de verrouillage sur Enqueue et Dequeue tant que ces méthodes ne sont pas thread safe – ULysses

+0

@ULysses: Le lien que j'ai fourni avait plusieurs implémentations différentes qui traitent déjà correctement les problèmes de sécurité des threads . Aucun mécanisme de synchronisation de thread supplémentaire n'est nécessaire pour le code dans ma réponse. –

+0

Je veux dire ce lien que vous avez donné http://blogs.msdn.com/b/toub/archive/2006/04/12/blocking-queues.aspx – ULysses

Questions connexes