自定义线程池C#问题

自定义线程池C#问题,c#,.net,multithreading,thread-safety,C#,.net,Multithreading,Thread Safety,因此,我有一个自定义线程池,它接收最大数量的线程,您可以在其中对项目进行排队。池将执行队列中的项目。问题是这个池的行为总是不同的。我创建了一个测试,该测试为该池提供X个操作数,并等待该池完成工作(这种等待是有限制的,但该限制足以使所有操作成功结束)。问题是,有时测试返回“成功”响应,但大多数情况下,它超过了时间限制和/或没有处理所有操作 代码: CustomThreadPool.cs public class CustomThreadPool : IDisposable {

因此,我有一个自定义线程池,它接收最大数量的线程,您可以在其中对项目进行排队。池将执行队列中的项目。问题是这个池的行为总是不同的。我创建了一个测试,该测试为该池提供X个操作数,并等待该池完成工作(这种等待是有限制的,但该限制足以使所有操作成功结束)。问题是,有时测试返回“成功”响应,但大多数情况下,它超过了时间限制和/或没有处理所有操作

代码:

CustomThreadPool.cs

    public class CustomThreadPool : IDisposable
    {
        #region Private Members

        private readonly Thread m_checkThread;

        #endregion

        #region Public Properties

        public int MaxNumberOfThreads { get; set; }
        private readonly object m_lock = new object();
        private int m_currentNumberOfThreads;
        public int CurrentNumberOfThreads
        {
            get
            {
                lock (m_lock)
                {
                    return m_currentNumberOfThreads;
                }
            }
            private set
            {
                lock (m_lock)
                {
                    m_currentNumberOfThreads = value;
                }
            }
        }
        public ConcurrentQueue<WorkItem> QueuedItems { get; set; }

        #endregion

        #region Constructor

        public CustomThreadPool(int maxNumberOfThreads)
        {
            MaxNumberOfThreads = maxNumberOfThreads;

            QueuedItems = new ConcurrentQueue<WorkItem>();
            m_checkThread = new Thread(CheckThread);
            m_checkThread.Start();
        }

        #endregion

        #region Public Methods

        public void QueueItem(object argument, Action<WorkItem> method, string token = "")
        {
            QueuedItems.Enqueue(new WorkItem { Argument = argument, Method = method, Token = token });
        }

        public List<WorkItem> Stop()
        {
            m_checkThread.Abort();
            List<WorkItem> result = new List<WorkItem>();
            while (QueuedItems.Count > 0)
            {
                WorkItem wi;
                QueuedItems.TryDequeue(out wi);
                if (wi != null)
                    result.Add(wi);
            }
            CurrentNumberOfThreads = 0;
            return result;
        }

        #endregion

        #region Private Methods

        // ReSharper disable once FunctionNeverReturns
        private void CheckThread()
        {
            while (true)
            {
                if (CurrentNumberOfThreads >= MaxNumberOfThreads || QueuedItems.Count == 0)
                {
                    Thread.Yield();
                }

                int availableThreads = MaxNumberOfThreads - CurrentNumberOfThreads;

                List<WorkItem> toBeProcessed = new List<WorkItem>();

                for (var i = 0; i < availableThreads; i++)
                {
                    WorkItem wi;
                    QueuedItems.TryDequeue(out wi);

                    if (wi != null)
                    {
                        toBeProcessed.Add(wi);
                    }
                }

                foreach (WorkItem item in toBeProcessed)
                {
                    CurrentNumberOfThreads++;
                    item.ExecutingThread = new Thread(ProcessItem);
                    item.ExecutingThread.Start(item);
                }

                Thread.Sleep(50);
            }
        }

        private void ProcessItem(object wi)
        {
            WorkItem item = (WorkItem)wi;
            item.Method.Invoke(item);
            CurrentNumberOfThreads--;
            item.ExecutingThread.Abort();
        }

        #endregion

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (disposing)
            {
                m_checkThread.Abort();
            }
        }
    }
公共类CustomThreadPool:IDisposable
{
#区域私人成员
私有只读线程m_checkThread;
#端区
#区域公共财产
public int MaxNumberOfThreads{get;set;}
私有只读对象m_lock=新对象();
私有int m_currentNumberOfThreads;
公共int CurrentNumberOfThreads
{
得到
{
锁(m_锁)
{
返回m_currentNumberOfThreads;
}
}
专用设备
{
锁(m_锁)
{
m_currentNumberOfThreads=值;
}
}
}
公共ConcurrentQueue QueuedItems{get;set;}
#端区
#区域构造函数
公共CustomThreadPool(int maxNumberOfThreads)
{
MaxNumberOfThreads=MaxNumberOfThreads;
QueuedItems=新的ConcurrentQueue();
m_checkThread=新线程(checkThread);
m_checkThread.Start();
}
#端区
#区域公共方法
public void QueueItem(对象参数、操作方法、字符串标记=“”)
{
Enqueue(新工作项{Argument=Argument,Method=Method,Token=Token});
}
公共列表停止()
{
m_checkThread.Abort();
列表结果=新列表();
而(QueuedItems.Count>0)
{
工作项目wi;
QueuedItems.TryDequeue(输出wi);
如果(wi!=null)
结果:添加(wi);
}
CurrentNumberOfThreads=0;
返回结果;
}
#端区
#区域私有方法
//ReSharper禁用一次功能NeverReturns
私有void CheckThread()
{
while(true)
{
如果(CurrentNumberOfThreads>=MaxNumberOfThreads | | QueuedItems.Count==0)
{
螺纹屈服强度();
}
int availableThreads=MaxNumberOfThreads-CurrentNumberOfThreads;
List toBeProcessed=新列表();
对于(变量i=0;i
测试:

private List EndedOperations=new List();
private List StartedOperations=新列表();
公共void CheckThreadPool()
{
int工作时间=100;
int numberOfOperations=100;
int numberOfThreads=10;
int cycles=numberOfOperations/numberOfThreads;
int totalTime=工作时间*2*个周期;
秒表sw=新秒表();
sw.Start();
CustomThreadPool池=新的CustomThreadPool(numberOfThreads);
for(int i=0;i0&&sw.ElapsedMillisecondsprivate List<int> EndedOperations = new List<int>();
private List<int> StartedOperations = new List<int>();

public void CheckThreadPool()
    {
        int workTime = 100;
        int numberOfOperations = 100;
        int numberOfThreads = 10;
        int cycles = numberOfOperations / numberOfThreads;
        int totalTime = workTime * 2 * cycles;
        Stopwatch sw = new Stopwatch();
        sw.Start();
        CustomThreadPool pool = new CustomThreadPool(numberOfThreads);

        for (int i = 0; i < numberOfOperations; i++)
        {
            pool.QueueItem(new WorkInfo(i, workTime), DoWork);
        }
        Thread.Sleep(workTime);
        bool queueEmpty = false, operationsDone = false;
        while (pool.CurrentNumberOfThreads > 0 && sw.ElapsedMilliseconds < totalTime)
        {
            if (pool.QueuedItems.Count == 0 && !queueEmpty)
            {
                queueEmpty = true;
                Debug.WriteLine("Queue emptied at: {0}, operations left: {1}", sw.ElapsedMilliseconds, numberOfOperations - EndedOperations.Count);
            }
            if (EndedOperations.Count == numberOfOperations && !operationsDone)
            {
                operationsDone = true;
                Debug.WriteLine("Operations done at: {0}, number of threads: {1}", sw.ElapsedMilliseconds, pool.CurrentNumberOfThreads);
            }
            Thread.Yield();
        }
        sw.Stop();
        pool.Dispose();
        Thread.Sleep(workTime);
        Debug.WriteLine("Test ended with {0} unprocessed operations", numberOfOperations - EndedOperations.Count);
        for (int i = 0; i < numberOfOperations; i++)
        {
            if (!EndedOperations.Contains(i))
                Debug.WriteLine("Operation {0} was not fully processed", i);
            if (!StartedOperations.Contains(i))
                Debug.WriteLine("Operation {0} has never started", i);
        }
        Assert.IsTrue(sw.ElapsedMilliseconds < totalTime,
            string.Format(@"The pool did not stop in useful time. 
                                Remaining threads : {0}
                                Remaining queued items : {1}
                                Remaining operations: {2}",
                                pool.CurrentNumberOfThreads, pool.QueuedItems.Count, numberOfOperations - EndedOperations.Count));
        Assert.IsTrue(pool.QueuedItems.Count == 0,
            string.Format(@"Not all items were processed. 
                                Remaining : {0}
                                Processing time : {1}",
                                pool.QueuedItems.Count, sw.ElapsedMilliseconds));
    }

    private void DoWork(WorkItem wi)
    {
        WorkInfo info = (WorkInfo)wi.Argument;
        try
        {
           StartedOperations.Add(info.Id);
            Thread.Sleep(info.TestTime);
            EndedOperations.Add(info.Id);
        }
        catch(Exception ex)
        {
            Debug.WriteLine("id: {0}, ex: {1}", info.Id, ex.Message);
        }

    }
CurrentNumberOfThreads++;
System.Threading.Interlocked.Increment(ref m_CurrentNumberOfThreads);
CurrentNumberOfThreads--;
System.Threading.Interlocked.Decrement(ref m_CurrentNumberOfThreads);