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