2010-06-30 4 views
2

Je suis en train de contourner la limite de la poignée de wait64 que .Net 3.5 imposeThreadPool - WaitAll 64 Poignée limite

J'ai vu ce fil: Workaround for the WaitHandle.WaitAll 64 handle limit?

Je comprends l'idée générale, mais je suis la difficulté parce que je ne suis pas en utilisant un délégué mais

Je travaille essentiellement de cet exemple: http://msdn.microsoft.com/en-us/library/3dasc8as%28VS.80%29.aspx

ce lien http://www.switchonthecode.com/tutorials/csharp-tutorial-using-the-threadpool est similaire mais encore une fois la variable int gardant la trace des tâches est une variable membre.

Où dans l'exemple ci-dessus passerais-je l'entier threadCount? Est-ce que je le passe dans la méthode de rappel en tant qu'objet? Je pense que j'ai des problèmes avec la méthode de rappel et de passage par référence.

Merci Stephen,

Ce lien est pas tout à fait clair pour moi.

Permettez-moi de poster mon code pour me aider à préciser:

for (int flows = 0; flows < NumFlows; flows++) 
{ 
ResetEvents[flows] = new ManualResetEvent(false); 
ICalculator calculator = new NewtonRaphson(Perturbations); 
Calculators[flows] = calculator; 
ThreadPool.QueueUserWorkItem(calculator.ThreadPoolCallback, flows); 
} 
resetEvent.WaitOne(); 

Où puis-je passer ma variable THREADCOUNT. Je suppose qu'il doit être décrémenté dans calculator.ThreadPoolCallback?

+0

Qu'est-ce que l'entier numérique numTask? –

+0

Désolé, je crois que je voulais dire "threadCount" du premier lien. – bearrito

+1

Point technique mineur: la limite de 64-handle est imposée par l'API Win32, pas .NET 3.5. Ainsi, chaque programme sur Windows a la même limitation. –

Répondre

0

Une méthode anonyme peut-être plus facile:

int threadCount = 0; 
for (int flows = 0; flows < NumFlows; flows++) 
{ 
    ICalculator calculator = new NewtonRaphson(Perturbations); 
    Calculators[flows] = calculator; 

    // We're about to queue a new piece of work: 
    // make a note of the fact a new work item is starting 
    Interlocked.Increment(ref threadCount); 
    ThreadPool.QueueUserWorkItem(
     delegate 
     { 
      calculator.ThreadPoolCallback(flows); 

      // We've finished this piece of work... 
      if (Interlocked.Decrement(ref threadCount) == 0) 
      { 
       // ...and we're the last one. 
       // Signal back to the main thread. 
       resetEvent.Set(); 
      } 
     }, null); 
} 
resetEvent.WaitOne(); 
+0

Si vous regardez les liens fournis, vous pouvez voir que j'essaie d'éviter d'utiliser des méthodes anonymes. – bearrito

+0

Je ne vois pas pourquoi vous évitez les méthodes anonymes - êtes-vous en train de cibler les runtimes .NET 1.0 ou 1.1? –

+0

Il y a un bug si subtil ici. Le 'WaitOne' et le' Interlocked.Decrement' courront causant 'WaitOne' de retourner trop tôt si le dernier élément de travail a été mis en file d'attente * et * achevé avant que l'itération suivante de la boucle ait une chance de' Interlocked.Increment'. –

1

Vous ne devriez pas utiliser plusieurs poignées d'attente pour attendre l'achèvement de plusieurs éléments de travail dans le ThreadPool. Non seulement cela n'est pas évolutif, mais vous finirez par tomber dans la limite de 64 handle imposée par la méthode WaitHandle.WaitAll (comme vous l'avez déjà fait). Le modèle correct à utiliser dans cette situation est un handle d'attente de comptage. Il en existe un disponible dans le téléchargement Reactive Extensions pour .NET 3.5 via la classe CountdownEvent.

var finished = new CountdownEvent(1); 
for (int flows = 0; flows < NumFlows; flows++) 
{ 
    finished.AddCount(); 
    ICalculator calculator = new NewtonRaphson(Perturbations); 
    Calculators[flows] = calculator; 
    ThreadPool.QueueUserWorkItem(
    (state) => 
    { 
     try 
     { 
     calculator.ThreadPoolCallback(state); 
     } 
     finally 
     { 
     finished.Signal(); 
     } 
    }, flows); 
} 
finished.Signal(); 
finished.Wait();