2010-09-23 6 views
6

J'essaie d'utiliser ThreadPool.RegisterWaitForSingleObject pour ajouter une minuterie à un ensemble de threads. Je crée 9 threads et j'essaye de donner à chacun d'entre eux une chance égale d'opération car pour le moment il semble y avoir un peu de famine si je les ajoute juste au pool de threads. J'essaie également d'implémenter un événement de réinitialisation manuelle car je souhaite que tous les 9 threads soient fermés avant de continuer. Quelle est la meilleure façon de s'assurer que chaque thread dans le pool de threads a une chance égale de courir car la fonction que j'appelle a une boucle et il semble que chaque thread (ou celui qui court en premier) reste bloqué dedans et les autres n'ont pas la chance de courir.La bonne façon d'implémenter ThreadPool.RegisterWaitForSingleObject

resetEvents = new ManualResetEvent[table_seats]; 
      //Spawn 9 threads 
      for (int i = 0; i < table_seats; i++) 
      { 
       resetEvents[i] = new ManualResetEvent(false); 
       //AutoResetEvent ev = new AutoResetEvent(false); 
       RegisteredWaitHandle handle = ThreadPool.RegisterWaitForSingleObject(autoEvent, ObserveSeat, (object)i, 100, false); 
      } 

      //wait for threads to exit 
      WaitHandle.WaitAll(resetEvents); 

Cependant, il n'a pas d'importance si j'utilise resetEvents [] ou ev ne semble fonctionner correctement. Suis-je en mesure de mettre en œuvre ceci ou suis-je (probablement) mal comprendre comment ils devraient travailler.

Merci, R.

Répondre

4

Je ne pas utiliser le RegisterWaitForSingleObject à cet effet. Les modèles que je vais décrire ici nécessitent le téléchargement Reactive Extensions depuis que vous utilisez .NET v3.5.

D'abord, pour attendre tous les éléments de travail du ThreadPool, utilisez la classe CountdownEvent. C'est beaucoup plus élégant et évolutif que d'utiliser plusieurs instances ManualResetEvent. De plus, la méthode WaitHandle.WaitAll est limitée à 64 poignées.

var finished = new CountdownEvent(1); 
for (int i = 0; i < table_seats; i++) 
{ 
    finished.AddCount(); 
    ThreadPool.QueueUserWorkItem(ObserveSeat); 
    (state) => 
    { 
     try 
     { 
     ObserveSeat(state); 
     } 
     finally 
     { 
     finished.Signal(); 
     } 
    }, i); 
} 
finished.Signal(); 
finished.Wait(); 

Deuxièmement, vous pouvez essayer d'appeler Thread.Sleep(0) après plusieurs itérations de la boucle pour forcer un changement de contexte afin que les rendements actuels de fil à un autre. Si vous voulez une stratégie de coordination beaucoup plus complexe, utilisez la classe Barrier. Ajoutez un autre paramètre à votre fonction ObserveSeat qui accepte ce mécanisme de synchronisation. Vous pouvez le fournir en le capturant dans l'expression lambda dans le code ci-dessus. Notez que bien que cette approche empêcherait certainement le problème de famine, elle pourrait limiter le débit des threads. Appeler SignalAndWait trop peut causer beaucoup de changement de contexte inutile, mais l'appeler trop peu peut causer beaucoup d'attente inutile. Vous devrez probablement régler AMOUNT pour obtenir l'équilibre optimal de débit et de famine. Je soupçonne qu'il pourrait y avoir une manière simple de faire l'accord dynamiquement.

+1

Merci, je n'ai pas encore eu le temps de le tester mais merci Brian pour la réponse. – flavour404

Questions connexes