2009-11-13 4 views
1

J'ai un problème avec Threadpooling ici, j'ai besoin d'aide s'il vous plaît. J'essaie d'écrire un générateur, et je dois permettre aux utilisateurs de générer jusqu'à 10 000 lignes avec le code ci-dessous. Le problème avec ceci est la ligneThread Pooling help

WaitHandle.WaitAll (doneEvents);

Ne peut gérer 64 WaitAll à la fois, Comment puis-je mieux appliquer le pool de threads à mon code dans ce cas?

public void GenerateInsertStatements(int iRequiredRows) 
     { 
      // One event is used for each row object 
      ManualResetEvent[] doneEvents = new ManualResetEvent[iRequiredRows]; 

      Row[] rows = new Row[iRequiredRows]; 
      for (int i = 0; i < iRequiredRows; i++) 
      { 
       doneEvents[i] = new ManualResetEvent(false); 
       Row row = new Row(this.Name, this.TableColumns, doneEvents[i]); 
       rows[i] = row; 
       ThreadPool.QueueUserWorkItem(row.ThreadPoolCallback, i); 
      } 

      WaitHandle.WaitAll(doneEvents); 


      using (sr = new StreamWriter(this.Name + ".sql")) 
      { 
       for(int i=0; i<rows.Length; i++) 
       { 
        WriteStatementToFile(i, rows[i].GeneratedInsertStatement); 
       } 
      } 
     } 

Merci à l'avance

Répondre

0

Comme il a déjà été suggéré d'utiliser un compteur et un seul ManualResetEvent devrait fonctionner correctement pour vous. Ci-dessous est la classe ThreadPoolWait prise de .NET Matters: ThreadPoolWait and HandleLeakTracer (voir Figure 3 Une meilleure mise en œuvre de ThreadPoolWait pour plus d'informations)

public class ThreadPoolWait : IDisposable 
{ 
    private int _remainingWorkItems = 1; 
    private ManualResetEvent _done = new ManualResetEvent(false); 

    public void QueueUserWorkItem(WaitCallback callback) 
    { 
     QueueUserWorkItem(callback, null); 
    } 

    public void QueueUserWorkItem(WaitCallback callback, object state) 
    { 
     ThrowIfDisposed(); 
     QueuedCallback qc = new QueuedCallback(); 
     qc.Callback = callback; 
     qc.State = state; 
     lock (_done) _remainingWorkItems++; 
     ThreadPool.QueueUserWorkItem(new WaitCallback(HandleWorkItem), qc); 
    } 

    public bool WaitOne() { return WaitOne(-1, false); } 

    public bool WaitOne(TimeSpan timeout, bool exitContext) 
    { 
     return WaitOne((int)timeout.TotalMilliseconds, exitContext); 
    } 

    public bool WaitOne(int millisecondsTimeout, bool exitContext) 
    { 
     ThrowIfDisposed(); 
     DoneWorkItem(); 
     bool rv = _done.WaitOne(millisecondsTimeout, exitContext); 
     lock (_done) 
     { 
      if (rv) 
      { 
       _remainingWorkItems = 1; 
       _done.Reset(); 
      } 
      else _remainingWorkItems++; 
     } 
     return rv; 
    } 

    private void HandleWorkItem(object state) 
    { 
     QueuedCallback qc = (QueuedCallback)state; 
     try { qc.Callback(qc.State); } 
     finally { DoneWorkItem(); } 
    } 

    private void DoneWorkItem() 
    { 
     lock (_done) 
     { 
      --_remainingWorkItems; 
      if (_remainingWorkItems == 0) _done.Set(); 
     } 
    } 

    private class QueuedCallback 
    { 
     public WaitCallback Callback; 
     public object State; 
    } 

    private void ThrowIfDisposed() 
    { 
     if (_done == null) throw new ObjectDisposedException(GetType().Name); 
    } 

    public void Dispose() 
    { 
     if (_done != null) 
     { 
      ((IDisposable)_done).Dispose(); 
      _done = null; 
     } 
    } 
} 
0

probablement pas la solution la plus efficace, mais il devrait fonctionner indépendamment de la 64 attente gère limite:

for(int i = 0; i < iRequiredRows; i++) 
    doneEvents[i].WaitOne(); 
+0

Avez-vous une meilleure idée de la façon dont je pouvais faire ce qui précède s'il vous plaît? Je commence tout juste à comprendre comment utiliser le thread-threading pour la solution afin de générer jusqu'à 10 000 lignes. – Kobojunkie

+0

Eh bien, si j'avais une meilleure idée je l'aurais posté en premier lieu;). La solution de Gonzalo semble bonne aussi, honnêtement, je ne sais pas lequel est le meilleur ... –

1

j'utiliser un seul WaitHandle et un int. Comme:

int done_when_zero; // This is a field of the class 
ManualResetEvent evt = new ManualResetEvent (false); // Field 
... 
done_when_zero = iRequiredRows; // This goes before the loop 
... 
evt.WaitOne(); // this goes after the loop 
evt.Reset(); // Prepare for next execution if needed 

Et puis, à la fin de ThreadPoolCallback:

if (Interlocked.Decrement (ref done_when_zero)) <= 0) 
    evt.Set();