我坚信通过重塑来学习。凭借这种心态,我开始实现自定义线程池。我为自己设定的目标是:
我成功实现了上述目标,但希望验证我在stackoverflow上与专家一起采取的方法。此外,想了解是否有更好的方法或多线程专家如何解决这个问题。以下段落提到了我所面临的挑战以及如何解决它。
我创建的线程池在内部维护了一个工作项队列,所有工作线程都从中挑选了该项,然后对其进行处理。每当一个新项目排队时,它就会发出一个事件信号,这样任何一个免费线程都可以获取它并执行它。
我开始使用autoresetevent来向队列中的任何新工作项发出等待线程的信号,但我遇到了丢失信号事件的问题。当多个项目排队并且没有可用于处理项目的空闲线程时,就会发生这种情况。未处理的总项目与由于重叠集(信令)事件而丢失的总信号事件相同。
为了解决丢失信号事件的问题,我在autoresetevent之上创建了一个包装器,并用它来代替autoresetevent。它解决了这个问题。以下是相同的代码清单:
public static class CustomThreadPool
{
static CustomThreadPool()
{
for (int i = 0; i < minThreads; i++)
_threads.Add(
new Thread(ThreadFunc) { IsBackground = true }
);
_threads.ForEach((t) => t.Start());
}
public static void EnqueWork(Action action)
{
_concurrentQueue.Enqueue(action);
_enqueEvent.Set();
}
private static void ThreadFunc()
{
Action action = null;
while (true)
{
_enqueEvent.WaitOne();
_concurrentQueue.TryDequeue(out action);
action();
}
}
private static ConcurrentQueue<Action> _concurrentQueue = new ConcurrentQueue<Action>();
private static List<Thread> _threads = new List<Thread>();
private static CountAutoResentEvent _enqueEvent = new CountAutoResentEvent();
private static object _syncObject = new object();
private const int minThreads = 4;
private const int maxThreads = 10;
public static void Test()
{
CustomThreadPool.EnqueWork(() => {
for (int i = 0; i < 10; i++) Console.WriteLine(i);
Console.WriteLine("****First*****");
});
CustomThreadPool.EnqueWork(() =>
{
for (int i = 0; i < 10; i++) Console.WriteLine(i);
Console.WriteLine("****Second*****");
});
CustomThreadPool.EnqueWork(() =>
{
for (int i = 0; i < 10; i++) Console.WriteLine(i);
Console.WriteLine("****Third*****");
});
CustomThreadPool.EnqueWork(() =>
{
for (int i = 0; i < 10; i++) Console.WriteLine(i);
Console.WriteLine("****Fourth*****");
});
CustomThreadPool.EnqueWork(() =>
{
for (int i = 0; i < 10; i++) Console.WriteLine(i);
Console.WriteLine("****Fifth*****");
});
}
}
public class CountAutoResentEvent
{
public void Set()
{
_event.Set();
lock (_sync)
_countOfSet++;
}
public void WaitOne()
{
_event.WaitOne();
lock (_sync)
{
_countOfSet--;
if (_countOfSet > 0)
_event.Set();
}
}
private AutoResetEvent _event = new AutoResetEvent(false);
private int _countOfSet = 0;
private object _sync = new object();
}
现在,我几乎没有问题:
感谢。
答案 0 :(得分:1)
从我所看到的,我说它是正确的。我喜欢你使用ConcurrentQueue
并且没有实现自己的同步队列。这是一团糟,很可能不会像现有的那样快。
我只想指出,您的自定义“信号机制”实际上与信号量非常相似:一个允许多个线程进入临界区的锁。此功能已存在于Semaphore类中。