介绍
在上一篇c#自己实现线程池功能(一)中,我们基本实现了一个可以运行的程序,而不能真正的称作线程池。由于是上篇中的代码有个致命的bug那就是没有任务是并不是等待,而是疯狂的进行while循环,并试图lock任务链表,这样带来的问题的就是性能相当低下,程序反映速度很慢(当加入一个新任务后,要过很久这个job才开始运行)造成的原因就是刚才所说的。
为了解决这个问题我们就需要使用某种方法使得程序能够让进程同步。
方法一
使用信号量
我们为了减少对task任务的加锁操作,只有当task不为空时才进行试探。我们的信号量就代表的是任务表里面的数量,当s.WaitOne();成功后我们才开始加锁,并取出任务
while (flag && TaskQueue != null)
{
//等待任务
ThreadPoolManager.s.WaitOne();
//获取任务
lock (TaskQueue)
{
try
{
if (TaskQueue.Count > 0)
task = TaskQueue.Dequeue();
else
task = null;
}
catch (Exception)
{
task = null;
}
if (task == null)
continue;
}
在ThreadPoolManager类中加入两个变量
//由于采用信号量需要定义一个
public int MaxJobNum = 1000;
public static Semaphore s;
并在初始化这个类时 初始化信号量 s = new Semaphore(0, MaxJobNum);
这样就能够实现同步
下面给出一个测试类
static void Main(string[] args)
{
ThreadPoolManager tpm = new ThreadPoolManager(2);
TestTask t1 = new TestTask("task1");
TestTask t2 = new TestTask("task2");
TestTask t3 = new TestTask("task3");
TestTask t4 = new TestTask("task4");
TestTask t5 = new TestTask("task5");
TestTask t6 = new TestTask("task6");
TestTask t7 = new TestTask("task7");
TestTask t8 = new TestTask("task8");
TestTask t9 = new TestTask("task9");
tpm.AddTask(t1);
tpm.AddTask(t2);
tpm.AddTask(t3);
tpm.AddTask(t4);
tpm.AddTask(t5);
tpm.AddTask(t6);
tpm.AddTask(t7);
tpm.AddTask(t8);
tpm.AddTask(t9);
}
方法二
我们不是用信号量,我们使用AutoResetEvent来实现同步
第一步,在ThreadPoolManager初始化时候创建一个 locks = new AutoResetEvent(false);
当AddTask的时候locks.Set();通知等待的操作。
然后我们对WorkThread的run函数做一个小小的修改
public void run()
{
while (flag && TaskQueue != null)
{
//等待任务
//ThreadPoolManager.sep.WaitOne();
//等待任务
while (TaskQueue.Count == 0 && flag)
{
try
{
ThreadPoolManager.locks.WaitOne();
}
catch (Exception)
{
}
}
//获取任务
lock (TaskQueue)
{
try
{
task = TaskQueue.Dequeue();
}
catch (Exception)
{
task = null;
}
if (task == null)
continue;
}
try
{
task.SetEnd(false);
task.StartTask();
}
catch (Exception)
{
}
try
{
if (!task.IsEnd())
{
task.SetEnd(false);
task.EndTask();
}
}
catch (Exception)
{
}
}//end of while
}
只有当task列表的数量为0时我们才阻塞,直到AddTask的时候才继续下去