线程池帮助

时间:2009-11-13 02:33:27

标签: c# multithreading

在这里遇到Threadpooling的一些问题,我需要一些帮助。我正在尝试编写一个Generator,我需要允许用户使用下面的代码生成多达10,000行。问题是这一行

WaitHandle.WaitAll的(doneEvents);

一次只能处理64个WaitAll,在这种情况下,如何才能最好地将线程池应用于我的代码?

 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);
                }
            }
        }

提前致谢

3 个答案:

答案 0 :(得分:1)

我只使用一个WaitHandle和一个int。像:

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

然后,在ThreadPoolCallback结束时:

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

答案 1 :(得分:0)

可能不是最有效的解决方案,但它应该可以工作,无论64个等待句柄限制:

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

答案 2 :(得分:0)

因为已经建议使用计数器,单个ManualResetEvent应该可以正常工作。下面是取自.NET Matters: ThreadPoolWait and HandleLeakTracer的ThreadPoolWait类(更多信息参见图3 ThreadPoolWait的更好实现)

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;
        }
    }
}